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

在CodeDomProvider(Roslyn)中使用C#6功能,c#,.net,roslyn,string-interpolation,codedom,C#,.net,Roslyn,String Interpolation,Codedom,当我编译我的文件时,我得到: cs(347):错误:意外字符“$” 有人知道如何让字符串插值与CodeDom编译一起工作吗 我找到了这个链接: 所以我试着: CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" ); CompilerParameters objCompilerParameters = new CompilerParameters(); ... CompilerResults o

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

cs(347):错误:意外字符“$”

有人知道如何让字符串插值与CodeDom编译一起工作吗

我找到了这个链接:

所以我试着:

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

CompilerParameters objCompilerParameters = new CompilerParameters();

...

CompilerResults objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );
我曾尝试使用Thomas Levesque的建议:

************** 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)
但我得到:

CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
我不知道为什么它试图在我的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


内置的CodeDOM提供程序不支持C#6。改用这个:

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

只需更改这一行:

************** 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)
为此:

CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" );
更新日期:2018年3月

警告,NuGet版本1.0.6。。。1.0.8将 不将/roslyn文件夹复制到非web上的生成输出目录 项目。最好坚持1.0.5

使用C#6特性的运行时编译需要一个新的编译器,如@thomas levesque所述。可以使用nuget包安装此编译器

对于桌面应用程序,存在一个问题。ASP.NET团队以其无穷的智慧将编译器的路径硬编码为
\bin\roslyn\csc.exe
参见

如果您的桌面应用程序被编译为
\myapp\app.exe
,则roslyn编译器将位于
\myapp\roslyn\csc.exe
但是
CSharpCodeProvider
csc.exe
解析为
\myapp\bin\roslyn\csc.exe

据我所知,你有两个选择

  • 创建生成后和/或安装例程,将
    \roslyn
    子目录移动到
    \bin\roslyn
  • 通过反射黑魔法修复运行时代码
  • 下面是#2,通过将
    CSharpCodeProvider
    作为实用程序类中的属性公开

    CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
    
    使用系统反射;
    使用Microsoft.CodeDom.Providers.DotNetCompilerPlatform;
    静态惰性代码提供程序{get;}=new Lazy(()=>{
    var csc=新的CSharpCodeProvider();
    var设置=csc
    .GetType()
    .GetField(“_compilerSettings”,BindingFlags.Instance | BindingFlags.NonPublic)
    .GetValue(csc);
    变量路径=设置
    .GetType()
    .GetField(“_compilerFullPath”,BindingFlags.Instance | BindingFlags.NonPublic);
    path.SetValue(设置)((字符串)path.GetValue(设置)).Replace(@“bin\roslyn\”,@“roslyn\”);
    返回csc;
    });
    
    面临完全损坏的编译器的同样问题,并找到了除中列出的解决方案之外的第三种解决方案,通过查看库的反编译源代码,我发现,在设置硬编码路径
    {ProgramLocation}\bin\roslyn
    之前,它会搜索该位置的环境变量(也是硬编码的),如果设置了,它将使用该选项

    考虑到这一点,类似这样的代码也可以“修复”问题:

    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;
    });
    
    虽然这并没有诉诸于反射来搞乱内部,但它仍然依赖于实现细节,这样滥用环境变量感觉是不对的。我个人更喜欢这一点,而不是反射选项,但同时我知道两者都依赖于精确的实现(以及硬编码路径)


    由于这个问题,需要调用一个外部程序来做应该做的事情,我仍然认为这个库是完全被打破的。在上下文中,我试图使用

    System.CodeDom
    对一个库项目运行MSTest项目,但无论我是否有
    Microsoft.Net.Compilers
    Microsoft.CodeDom.Providers.DotNetCompilerPlatform
    被测项目引用的包,它总是提供一个实现C#5的编译器

    我对此的修正是:

    • 使用包
      Microsoft.CodeDom.Providers.DotNetCompilerPlatform
    • 将包
      PrivateAssets
      设置为
      contentfiles;分析仪
    • CompilerDirectoryPath
      设置传递到复制的目录
    PrivateAssets
    的属性是
    contentfiles;分析仪;生成
    ,因此要使引用项目也复制文件夹,需要从设置中删除
    build

    示例代码:

    //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
    
    var compiler=CodeDomProvider.CreateProvider(“cs”),新字典{
    {“CompilerDirectoryPath”,Path.Combine(Environment.CurrentDirectory,“roslyn”)}
    });
    

    使用
    Microsoft.Net.Compilers
    来实现这一点会有点繁琐,因为没有复制,但是在包的tools文件夹中指向CompilerDirectoryPath的最后一步是相同的。

    更新信息:即使发布了FW 4.8,您仍然无法使用C#8.0的所有新功能-发行版包含CSC,仅限于5.0版;但是,使用CSC时存在黑客攻击,与VS2019一起分发(是的,您必须安装它):

    var csprovider=new CSharpCodeProvider(新字典){
    [“CompilerDirectoryPath”]=@“c:\Program Files(x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn”,
    });
    选项+=“-langversion:8.0”;
    VaR PAR=新的编译参数:{GATEATION内存= true,编译程序选项=选项};
    PAR。参考程序集。添加(“微软.cPAR.DLL”);
    添加引用(“Soal.Cal.dll”);
    var res=csprovider.compileasemblyfromsource(第5段,“您的C#代码”);
    
    返回res.CompiledAssembly;//您的项目的目标是什么.NET Framework版本?我用“.NET Framework 4.6”的详细信息更新了我的问题。我应该指出的是,同样的代码在VisualStudio中编译得很好,但事实并非如此
    //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
    
    var compiler = CodeDomProvider.CreateProvider("cs", new Dictionary<string, string> {
        { "CompilerDirectoryPath", Path.Combine(Environment.CurrentDirectory, "roslyn") }
    });
    
    var csprovider = new CSharpCodeProvider(new Dictionary<string,string> {
        ["CompilerDirectoryPath"] = @"c:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn",
    });
    options += " -langversion:8.0 ";
    
    var par = new CompilerParameters { GenerateInMemory = true, CompilerOptions = options };
    par.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
    par.ReferencedAssemblies.Add("System.Core.dll");
    
    var res = csprovider.CompileAssemblyFromSource(par, "your C# code");
    
    return res.CompiledAssembly;// <- compiled result