【问题标题】:`Add-Type` C# 6+ features throwing errors`Add-Type` C# 6+ 功能引发错误
【发布时间】:2019-03-18 01:57:29
【问题描述】:

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

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 c#-6.0 powershell-v5.1 c# powershell roslyn


    【解决方案1】:

    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'
      

      这允许您在 powershell 中使用最新的 .NET 编译器,如果您捆绑了 CodeDomProvider dllroslyn 编译器,则可以将其与主脚本内联,或者您可以编译 C#将代码输出到dll,因此不必在每次运行脚本时都重新编译,从而更容易移植并加快脚本运行时间。

      【讨论】:

        【解决方案3】:

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

        Add-Type : 找不到路径 '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)
        

        不用说,关于这是否是一个错误,关于内胎有一些讨论。看起来该提供程序的目标是 ASP.NET 并且在那里做正确的事情。人们也对从哪里获取 csc.exe 意见不一。我怀疑这可能会继续是in flux

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

        【讨论】:

          猜你喜欢
          • 2023-04-04
          • 1970-01-01
          • 2019-04-08
          • 1970-01-01
          • 2019-09-07
          • 2015-11-05
          • 1970-01-01
          • 1970-01-01
          • 2011-04-11
          相关资源
          最近更新 更多