首页 文章

在CodeDomProvider(rosyln)中使用C#6功能

提问于
浏览
27
CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" );

CompilerParameters objCompilerParameters = new CompilerParameters();

...

CompilerResults objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );

当我编译我的文件时,我得到:

FileFunctions.cs(347):错误:意外字符'$'

有没有人知道如何使用CodeDom编译进行字符串插值?

我找到了这个链接:How to target .net 4.5 with CSharpCodeProvider?

所以我尝试过:

var providerOptions = new Dictionary<string, string>();
     providerOptions.Add( "CompilerVersion", "v4.0" );

     // Instantiate the compiler.
     CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp", providerOptions );

但我仍然得到同样的错误 .

我还将目标框架更新到.NET Framework 4.6 .

注意:我不能指定“v4.5”或“v4.6”或者我会得到:

************** Exception Text **************
System.InvalidOperationException: Compiler executable file csc.exe cannot be found.
   at System.CodeDom.Compiler.RedistVersionInfo.GetCompilerPath(IDictionary`2 provOptions, String compilerExecutable)
   at Microsoft.CSharp.CSharpCodeGenerator.FromFileBatch(CompilerParameters options, String[] fileNames)
   at Microsoft.CSharp.CSharpCodeGenerator.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromFileBatch(CompilerParameters options, String[] fileNames)
   at System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromFile(CompilerParameters options, String[] fileNames)
   at Dynamic.CodeDOMCompiler.CompileAllCodeFiles() in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\Core\CodeDOMCompiler.cs:line 93
   at NewForm.InitializeSystem() in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\NewForm.cs:line 179
   at NewForm.NewForm_Load(Object sender, EventArgs e) in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\NewForm.cs:line 111
   at System.Windows.Forms.Form.OnLoad(EventArgs e)

我尝试过使用Thomas Levesque的建议:

CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();

但后来我得到:

************** Exception Text **************
System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\bin\x86\Debug\bin\roslyn\csc.exe'.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at Microsoft.CodeDom.Providers.DotNetCompilerPlatform.Compiler.get_CompilerName()
   at Microsoft.CodeDom.Providers.DotNetCompilerPlatform.Compiler.FromFileBatch(CompilerParameters options, String[] fileNames)
   at Microsoft.CodeDom.Providers.DotNetCompilerPlatform.Compiler.CompileAssemblyFromFileBatch(CompilerParameters options, String[] fileNames)
   at System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromFile(CompilerParameters options, String[] fileNames)
   at Dynamic.CodeDOMCompiler.CompileAllCodeFiles() in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\Core\CodeDOMCompiler.cs:line 87
   at NewForm.InitializeSystem() in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\NewForm.cs:line 179
   at NewForm.NewForm_Load(Object sender, EventArgs e) in C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC#\NewForm.cs:line 111
   at System.Windows.Forms.Form.OnLoad(EventArgs e)

我不确定为什么它试图在我的bin目录的子文件夹中查找“csc.exe” .

此路径存在:

C:\ Users \ Derek.Morin \ Documents \ Visual Studio 2010 \ Projects \ ScriptCode \ ScriptCode.ConvertedToC#\ bin \ x86 \ Debug \ roslyn

但它正在寻找:

C:\ Users \ Derek.Morin \ Documents \ Visual Studio 2010 \ Projects \ ScriptCode \ ScriptCode.ConvertedToC#\ bin \ x86 \ Debug \ bin \ roslyn \ csc.exe

4 回答

  • 1

    内置的CodeDOM提供程序不支持C#6 . 请使用此代码:

    https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/

    它基于Roslyn并支持C#6功能 .

    只需改变这一行:

    CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" );
    

    对此:

    CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
    
  • 2

    更新:2018年3月警告,NuGet版本1.0.6 ... 1.0.8不会将/ roslyn文件夹复制到非Web项目上的构建输出目录 . 最好坚持1.0.5 https://github.com/aspnet/RoslynCodeDomProvider/issues/38

    使用C#6功能的运行时编译需要一个新的编译器,如@ thomas-levesque所述 . 可以使用nuget包Microsoft.CodeDom.Providers.DotNetCompilerPlatform安装此编译器 .

    对于桌面应用程序,存在问题 . ASP.NET团队以其无限的智慧将编译器的路径硬编码为 <runtime-directory>\bin\roslyn\csc.exehttps://github.com/dotnet/roslyn/issues/9483的讨论

    如果您的桌面应用程序编译为 \myapp\app.exe ,则roslyn编译器将位于 \myapp\roslyn\csc.exeBUT THE CSharpCodeProvider WILL RESOLVE csc.exe as \myapp\bin\roslyn\csc.exe

    据我所知,你有两个选择

    • 创建一个构建后和/或安装例程,将 \roslyn 子目录移动到 \bin\roslyn .

    • 通过反射黑魔法修复运行时代码 .

    这是#2,通过将 CSharpCodeProvider 公开为实用程序类中的属性 .

    using System.Reflection;
    using Microsoft.CodeDom.Providers.DotNetCompilerPlatform;
    
    static Lazy<CSharpCodeProvider> CodeProvider { get; } = new Lazy<CSharpCodeProvider>(() => {
        var csc = new CSharpCodeProvider();
        var settings = csc
            .GetType()
            .GetField("_compilerSettings", BindingFlags.Instance | BindingFlags.NonPublic)
            .GetValue(csc);
    
        var path = settings
            .GetType()
            .GetField("_compilerFullPath", BindingFlags.Instance | BindingFlags.NonPublic);
    
        path.SetValue(settings, ((string)path.GetValue(settings)).Replace(@"bin\roslyn\", @"roslyn\"));
    
        return csc;
    });
    
  • 23

    最近谈到这个问题 . 对于上下文,我试图使用 System.CodeDom 针对库项目运行MSTest项目,但是它总是给出了一个实现C#5的编译器,无论我是否有被测试项目引用的 Microsoft.Net.CompilersMicrosoft.CodeDom.Providers.DotNetCompilerPlatform 包 .

    我对此的解决方法是:

    • 使用包 Microsoft.CodeDom.Providers.DotNetCompilerPlatform

    • 将包 PrivateAssets 设为 contentfiles;analyzers

    • provider optionsCompilerDirectoryPath 设置为复制的目录

    PrivateAssetsdefault valuecontentfiles;analyzers;build ,因此要引用项目以复制文件夹需要从设置中删除 build .

    示例代码:

    var compiler = CodeDomProvider.CreateProvider("cs", new Dictionary<string, string> {
        { "CompilerDirectoryPath", Path.Combine(Environment.CurrentDirectory, "roslyn") }
    });
    

    使用 Microsoft.Net.Compilers 使其工作会稍微繁琐,因为没有复制,但是在包的工具文件夹中指向 CompilerDirectoryPath 的结束步骤是相同的 .

  • 20

    面对完全破碎的编译器的相同问题,除了Aaron's answer中列出的那些之外,还发现了第三个解决方案,通过查看我发现的库的反编译源,在设置硬编码路径 {ProgramLocation}\bin\roslyn 之前,它搜索环境变量(也是硬编码的那个位置,如果设置,它会使用它 .

    考虑到这一点,像这样的一些代码也会“解决”问题:

    //Set hardcoded environment variable to set the path to the library
    Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", "actual compiler location goes here", EnvironmentVariableTarget.Process);
    //Create compiler object
    CSharpCodeProvider compiler = new CSharpCodeProvider();
    //Clean up
    Environment.SetEnvironmentVariable("ROSLYN_COMPILER_LOCATION", null, EnvironmentVariableTarget.Process);
    
    //Use "compiler" variable to actually compile the dynamic code
    

    虽然这不会反映到内部的混乱,它仍然依赖于实现细节和滥用这样的环境变量只是感觉不对 . 我个人更喜欢这个,而不是反射选择,但同时我知道两者都依赖于确切的实现(以及硬编码路径) .

    由于这个问题,以及需要调用外部程序来完成应该在进程中完成的操作,我仍然认为这个库完全被破坏了 .

相关问题