在CodeDomProvider(rosyln)

时间:2015-07-26 17:00:21

标签: c# roslyn codedom string-interpolation

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 \项目\脚本代码\ ScriptCode.ConvertedToC#\ BIN \ 86 \调试\罗斯林

但它正在寻找:

  

C:\ Users \ Derek.Morin \ Documents \ Visual Studio   2010 \项目\脚本代码\ ScriptCode.ConvertedToC#\ BIN \ 86 \调试\ BIN \罗斯林\ CSC.EXE

5 个答案:

答案 0 :(得分:25)

  

更新: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.exe请参阅https://github.com/dotnet/roslyn/issues/9483上的讨论

如果您的桌面应用程序编译为\myapp\app.exe,则ros​​lyn编译器将位于\myapp\roslyn\csc.exeCSharpCodeProvider将重新设置csc.exe {{1} }}

据我所知,你有两个选择

  1. 创建一个构建后和/或安装例程,将\myapp\bin\roslyn\csc.exe子目录移至\roslyn
  2. 通过反射黑魔法修复运行时代码。
  3. 这是#2,通过将\bin\roslyn公开为实用程序类中的属性。

    CSharpCodeProvider

答案 1 :(得分:20)

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

this fiddle

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

只需更改此行:

library(lazyeval)
library(dplyr)
f1 <- function(dat, cname){
    #get the third argument i.e, 'cname'
    nm1 <- match.call()[[3]]
    #paste 'imputed' for renaming the new column later
    nm2 <- paste0(nm1, 'imputed')
    #create an numeric column index that will be removed in kmeans calc
    indx <- grep(cname, colnames(dat))
    #get the 'kmeans' of the columns other than the 'cname'
    clust <- kmeans(dat[,-indx],3)$cluster
    #group by 'clust' and create new column with 'mutate'
    dat %>%
       group_by(clust=clust) %>%
       mutate_(interp(~ifelse(is.na(v), mean(v, na.rm=TRUE), v),
                      v=as.name(cname))) %>% 
       #rename the column 
       setNames(., c(head(names(.),-1), nm2))     
   }

 f1(df1, 'x3')

到此:

v= lazy(cname)

答案 2 :(得分:3)

最近遇到了这个问题。就上下文而言,我试图使用System.CodeDom对库项目运行MSTest项目,但是无论我是否引用了Microsoft.Net.CompilersMicrosoft.CodeDom.Providers.DotNetCompilerPlatform软件包,它总是为实现C#5的编译器提供了帮助被测试的项目。

我对此的解决方法是:

  • 使用软件包Microsoft.CodeDom.Providers.DotNetCompilerPlatform
  • 将软件包PrivateAssets设置为contentfiles;analyzers
  • CompilerDirectoryPath设置为复制目录的provider options通过

PrivateAssets的{​​{3}}是contentfiles;analyzers;build,因此要引用项目也要复制文件夹,需要从设置中删除build

示例代码:

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

将其与Microsoft.Net.Compilers配合使用会比较麻烦,因为不会进行复制,但是将CompilerDirectoryPath指向软件包的tools文件夹的最后一步是相同的。

答案 3 :(得分:1)

面对完全破坏的编译器的相同问题,除了Aaron's answer中列出的那些之外,通过查看我发现的库的反编译源,在设置硬编码路径之前找到第三个解决方案{{ 1}}它搜索该位置的环境变量(也是硬编码的),如果设置,则使用它代替。

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

{ProgramLocation}\bin\roslyn

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

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

答案 4 :(得分:0)

更新的信息:即使发布了FW 4.8,您仍然不能使用C#8.0的所有新功能-发行版包含CSC,限于版本5.0;但是有使用VS2019分发的CSC的技巧(是的,您必须安装它):

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

尽管有显式选项“ GenerateInMemory”,但是无论如何,您的代码将被写入文件,然后才被编译。请记住,如果您希望您的应用程序运行时没有磁盘访问权限。