CodeDomProvider (Roslyn)使用c# 6的特性
本文关键字:使用 Roslyn CodeDomProvider | 更新日期: 2023-09-27 18:04:58
CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" );
CompilerParameters objCompilerParameters = new CompilerParameters();
...
CompilerResults objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );
当我编译我的文件,我得到:
FileFunctions.cs(347):错误:意外字符'$'
有没有人知道如何得到字符串插值与CodeDom编译工作?
我发现了这个链接:如何用CSharpCodeProvider瞄准。net 4.5 ?
所以我试了:
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: ' '用户德里克。莫林' ' Visual Studio的文档2010 ' ' ScriptCode ' ScriptCode项目。ConvertedToC # ' bin ' x86 '调试' roslyn
但是它正在寻找:
C: ' '用户德里克。莫林' ' Visual Studio的文档2010 ' ' ScriptCode ' ScriptCode.ConvertedToC项目# ' bin ' x86 '调试' bin ' roslyn ' csc.exe
更新:2018年3月
NuGet版本1.0.6…1.0.8将不要将/roslyn文件夹复制到非web上的构建输出目录项目。最好还是保持1.0.5https://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
, roslyn编译器将位于'myapp'roslyn'csc.exe
, 但是CSharpCodeProvider
将把csc.exe
解析为'myapp'bin'roslyn'csc.exe
据我所知,你有两个选择
- 创建构建后和/或安装例程,将
'roslyn
子目录移动到'bin'roslyn
。 通过反射黑魔法修复运行时代码。
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;
});
内置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();
面对完全损坏的编译器的相同问题,并找到了第三种解决方案,除了在Aaron的回答中列出的那些,通过查看库的反编译源,我发现,在设置硬编码路径{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
虽然这没有诉诸反射来扰乱内部,但它仍然依赖于实现细节,像这样滥用环境变量感觉是错误的。我个人更喜欢这种方法,而不是反射方法,但同时我知道两者都依赖于确切的实现(以及硬编码的路径)。
由于这个问题,并且需要调用外部程序来完成应该在进程中完成的工作,我仍然认为这个库是完全坏的。
最近遇到这个问题。对于上下文,我试图使用System.CodeDom
对库项目运行MSTest项目,但无论我是否有Microsoft.Net.Compilers
或Microsoft.CodeDom.Providers.DotNetCompilerPlatform
包被测试项目引用,它总是给出一个实现c# 5的编译器。
我的修复是:
- 使用
Microsoft.CodeDom.Providers.DotNetCompilerPlatform
包 - 设置
PrivateAssets
为contentfiles;analyzers
- 传递提供程序选项,并将
CompilerDirectoryPath
设置为复制目录
PrivateAssets
的默认值是contentfiles;analyzers;build
,因此要使引用项目也复制文件夹,需要从设置中删除build
。
示例代码:
var compiler = CodeDomProvider.CreateProvider("cs", new Dictionary<string, string> {
{ "CompilerDirectoryPath", Path.Combine(Environment.CurrentDirectory, "roslyn") }
});
将此与Microsoft.Net.Compilers
一起工作将稍微乏味一些,因为没有复制,但是将CompilerDirectoryPath
指向软件包的tools文件夹的最后一步是相同的。
更新信息:即使在发布FW 4.8之后,您仍然无法使用c# 8.0的所有新功能-发行版包含CSC,仅限于版本5.0;但是有一个hack可以使用CSC,与VS2019一起分发(是的,你必须安装它):
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",你的代码无论如何都会被写入文件,然后才会被编译。请记住,如果您希望应用程序在没有磁盘访问的情况下运行。
对于Microsoft.CodeDom.Providers.DotNetCompilerPlatform v.3.6.0.0,以下工作:
string RoslynPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "''roslyn''csc.exe";
CSharpCodeProvider Provider = new CSharpCodeProvider(new ProviderOptions(RoslynPath, 0));