“添加类型”C#6+具有抛出错误的功能

时间:2016-11-24 13:33:21

标签: c# powershell roslyn

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

Add-Type -ReferencedAssemblies $assemblies -TypeDefinition $source

功能不起作用,例如:

  

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

代码:

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

我正在使用

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

3 个答案:

答案 0 :(得分: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属性。

答案 1 :(得分: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,这样就不必在每次运行脚本时都重新编译它,从而可以更轻松地移植并缩短脚本运行时间。

答案 2 :(得分: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#
  3. 作为一名(小联盟)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。]