Использование функций C# 6 С CodeDomProvider (rosyln)
CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" );
CompilerParameters objCompilerParameters = new CompilerParameters();
...
CompilerResults objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );
когда я компилирую свои файлы, я получаю:
FileFunctions.cs (347): ошибка: неожиданный символ '$'
кто-нибудь знает, как заставить интерполяцию строк работать с компиляцией CodeDom?
я нашел эту ссылку: как настроить .net 4.5 с помощью CSharpCodeProvider?
поэтому я попытался:
var providerOptions = new Dictionary<string, string>();
providerOptions.Add( "CompilerVersion", "v4.0" );
// Instantiate the compiler.
CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp", providerOptions );
но я все еще получаю ту же ошибку.
Я также обновил целевую платформу до .NET Основы 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:UsersDerek.MorinDocumentsVisual Studio 2010ProjectsScriptCodeScriptCode.ConvertedToC#CoreCodeDOMCompiler.cs:line 93
at NewForm.InitializeSystem() in C:UsersDerek.MorinDocumentsVisual Studio 2010ProjectsScriptCodeScriptCode.ConvertedToC#NewForm.cs:line 179
at NewForm.NewForm_Load(Object sender, EventArgs e) in C:UsersDerek.MorinDocumentsVisual Studio 2010ProjectsScriptCodeScriptCode.ConvertedToC#NewForm.cs:line 111
at System.Windows.Forms.Form.OnLoad(EventArgs e)
Я попытался использовать предложение Томаса Левеска:
CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
но потом я получаю:
************** Exception Text **************
System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:UsersDerek.MorinDocumentsVisual Studio 2010ProjectsScriptCodeScriptCode.ConvertedToC#binx86Debugbinroslyncsc.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:UsersDerek.MorinDocumentsVisual Studio 2010ProjectsScriptCodeScriptCode.ConvertedToC#CoreCodeDOMCompiler.cs:line 87
at NewForm.InitializeSystem() in C:UsersDerek.MorinDocumentsVisual Studio 2010ProjectsScriptCodeScriptCode.ConvertedToC#NewForm.cs:line 179
at NewForm.NewForm_Load(Object sender, EventArgs e) in C:UsersDerek.MorinDocumentsVisual Studio 2010ProjectsScriptCodeScriptCode.ConvertedToC#NewForm.cs:line 111
at System.Windows.Forms.Form.OnLoad(EventArgs e)
Я не уверен, почему он пытается искать "КБК.exe" в папку Мои папку bin.
этот путь существует:
C:UsersDerek.MorinДокументыVisual Studio 2010ПроектыScriptCodeScriptCode.ConvertedToC#binx86Debugroslyn
но он искал:
C:UsersDerek.MorinДокументыVisual Studio 2010ПроектыScriptCodeScriptCode.ConvertedToC#binx86Debugbinroslyncsc.exe
4 ответов
встроенный поставщик 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();
Обновление: Март 2018
слово предостережения, 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
, компилятор roslyn будет расположен по адресу \myapp\roslyn\csc.exe
, НО CSharpCodeProvider
РАЗРЕШИТ 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;
});
столкнулся с той же проблемой полностью сломанного компилятора и нашел третье решение в дополнение к перечисленным в Аарон, посмотрев на декомпилированный источник библиотеки, я нашел это, прежде чем установить жестко закодированный путь {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
пока это не прибегает к рефлексии, чтобы возиться с внутренними, он по-прежнему полагается на детали реализации и злоупотребление переменными среды, как это просто кажется неправильным. Мне лично это нравится больше, чем альтернатива отражения, но в то же время я знаю, что оба опираются на точную реализацию (а также на жестко закодированный путь).
из-за этой проблемы и необходимости вызова внешней программы для выполнения того, что должно быть сделано в процессе, я все еще считаю эту библиотеку полностью сломана.
недавно столкнулся с этой проблемой. Для контекста я пытался запустить проект MSTest против проекта библиотеки, используя System.CodeDom
, но он всегда давал компилятор, который реализовал C# 5 независимо от того, имел ли я Microsoft.Net.Compilers
или Microsoft.CodeDom.Providers.DotNetCompilerPlatform
пакеты, на которые ссылается тестируемого проекта.
мое исправление для этого было:
- использовать пакет
Microsoft.CodeDom.Providers.DotNetCompilerPlatform
- комплект поставки
PrivateAssets
tocontentfiles;analyzers
- передать параметры поставщика С
CompilerDirectoryPath
набор в скопированный каталог
на значение по умолчанию на PrivateAssets
is contentfiles;analyzers;build
, поэтому получение ссылок на проекты, чтобы также скопировать папку, требует удаления build
из настройки.
пример кода:
var compiler = CodeDomProvider.CreateProvider("cs", new Dictionary<string, string> {
{ "CompilerDirectoryPath", Path.Combine(Environment.CurrentDirectory, "roslyn") }
});
заставить это работать с Microsoft.Net.Compilers
было бы немного более утомительно, поскольку копия не сделана, но конечный шаг указания CompilerDirectoryPath
в папке инструментов пакета то же самое.