`Add-Type` C#6+具有抛出错误的功能

问题描述 投票:3回答:3

我正在尝试使用此命令在中编译源代码:

Add-Type -ReferencedAssemblies $assemblies -TypeDefinition $source

功能不起作用,例如:

Add-Type : c:\Users\...\AppData\Local\Temp\2\d2q5hn5b.0.cs(101) : Unexpected character '$'

代码:

new Problem($"... ({identifier})", node)

我正在使用

有没有办法来解决这个问题?

c# powershell roslyn
3个回答
7
投票

Powershell uses CodeDomProvider to compile their assemblies.框架提供的版本只支持C#5,因此默认情况下没有新功能可用。

但是,如果你提供另一个CodeDomProvider,你可以编译任何语言,也可以编译C#6。 There is a CodeDomProvider available for Roslyn(新的.NET编译器)。你可以download it from NuGet并使用Add-Type包括组件。然后创建编译器的实例并将其传递给-CodeDomProvider属性。


2
投票

为了扩展Patrick Hoffmans's solution,我对使用unbob's solution中的反射方法感到有点不舒服,因为这可能会在未来破坏。

我制定了以下powershell代码,它使用.NET命名类和接口:

#requires -Version 5

# download https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/ and extract with 7-zip to a location, enter that location on the next line
$DotNetCodeDomLocation = 'C:\Utils\microsoft.codedom.providers.dotnetcompilerplatform.2.0.1'
Add-Type -Path "$DotNetCodeDomLocation\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll"

# using Invoke-Expression moves this class definition to runtime, so it will work after the add-type and the ps5 class interface implementation will succeed
# This uses the public interface ICompilerSettings instead of the private class CompilerSettings
Invoke-Expression -Command @"
class RoslynCompilerSettings : Microsoft.CodeDom.Providers.DotNetCompilerPlatform.ICompilerSettings
{
    [string] get_CompilerFullPath()
    {
        return "$DotNetCodeDomLocation\tools\RoslynLatest\csc.exe"
    }
    [int] get_CompilerServerTimeToLive()
    {
        return 10
    }
}
"@
$DotNetCodeDomProvider = [Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider]::new([RoslynCompilerSettings]::new())

然后可以在以下示例中使用它:

  • 要使用汇编参考示例直接向powershell实例添加类型(需要将roslyn编译器和上面的代码与您的脚本捆绑在一起): Add-Type -CodeDomProvider $DotNetCodeDomProvider -TypeDefinition $your_source_code_block -ReferencedAssemblies @([System.Reflection.Assembly]::GetAssembly([hashtable]).Location)
  • 要将代码编译为dll以便在将来/其他脚本中加载(只需要将生成的dll文件与脚本捆绑在一起): $DotNetAssemblyParameters = [System.CodeDom.Compiler.CompilerParameters]::new( @([System.Reflection.Assembly]::GetAssembly([hashtable]).Location), 'path_and_name_for_saved.dll', $false ) # you can adjust more compilation settings here if you want, see # https://docs.microsoft.com/en-us/dotnet/api/system.codedom.compiler.compilerparameters?view=netframework-4.7.2 $compilationResults = $DotNetCodeDomProvider.CompileAssemblyFromSource( $DotNetAssemblyParameters, $your_source_code_block )

编译后的dll可以与简单的Add-Type一起使用:

Add-Type -Path 'path_and_name_for_saved.Dll'

如果捆绑.NET powershellCodeDomProvider编译器,这允许你使用dll中的最新roslyn编译器内联你的主脚本,或者你可以将C#代码编译成dll,这样就不必每次都重新编译脚本运行的时间,允许更容易的可移植性和更快的脚本运行时间。


1
投票

当我尝试Hoffman先生的方法时,我收到以下错误:

Add-Type : Could not find a part of the path 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\bin\roslyn\csc.exe'.

user1676558 mentions two solutions

  1. 包含针对此特定问题的修复程序的NuGet package
  2. 一个snippet of C#反映了违规的私人领域并修复它

作为一个(小联盟)PowerShell黑客,我基于对source code的检查提出了我自己的PowerShellian解决方案:

$dncpTypes = Add-Type -Path C:\<path where I put the dll>\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll -PassThru
$dncpTypTab = [ordered]@{}
$dncpTypes | %{$dncpTypTab[$_.Name] = $_}

$compSetCtor    = $dncpTypTab.CompilerSettings.GetConstructor(@([string],[int]))
$compSettings   = $compSetCtor.Invoke(@('C:\Program Files (x86)\MSBuild\14.0\Bin\csc.exe', 10))
$cscpOtherCtor  = $dncpTypTab.CSharpCodeProvider.GetConstructor('NonPublic,Instance', $null, @($dncpTypTab.ICompilerSettings), $null)
$roslynProvider = $cscpOtherCtor.Invoke($compSettings)

毋庸置疑,关于这是否是一个错误,有关于innertubes的一些讨论。看起来提供程序是针对ASP.NET的,并在那里做正确的事情。人们也不同意在哪里拿起csc.exe。我怀疑这可能继续是in flux

[后来编辑:在VS2017中,csc似乎生活在$ {env:ProgramFiles(x86)} \ Microsoft Visual Studio \ 2017 \ Enterprise \ MSBuild \ 15.0 \ Bin \ Roslyn \ csc.exe。

© www.soinside.com 2019 - 2024. All rights reserved.