c# roslyn codedom string-interpolation

Usando las características de C#6 con CodeDomProvider(rosyln)



roslyn string-interpolation (4)

CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" ); CompilerParameters objCompilerParameters = new CompilerParameters(); ... CompilerResults objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );

Cuando compilo mis archivos obtengo:

FileFunctions.cs (347): Error: carácter inesperado ''$''

¿Alguien sabe cómo hacer que la interpolación de cadenas funcione con la compilación de CodeDom?

Encontré este enlace: ¿Cómo apuntar .net 4.5 con CSharpCodeProvider?

Así que intenté:

var providerOptions = new Dictionary<string, string>(); providerOptions.Add( "CompilerVersion", "v4.0" ); // Instantiate the compiler. CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp", providerOptions );

Pero sigo teniendo el mismo error.

También actualicé el marco de destino a .NET Framework 4.6.

NOTA: No puedo especificar "v4.5" o "v4.6" o obtendré:

************** 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)

He intentado usar la sugerencia de Thomas Levesque:

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

Pero luego me sale:

************** 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)

No estoy seguro de por qué está intentando buscar "csc.exe" en una subcarpeta de mi directorio bin.

Este camino existe:

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

Pero estaba buscando:

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


Actualización: marzo 2018

Por precaución, la versión 1.0.6 ... 1.0.8 de NuGet no copiará la carpeta / roslyn al directorio de resultados de compilación en proyectos que no sean web. Mejor palo con 1.0.5 https://github.com/aspnet/RoslynCodeDomProvider/issues/38

La compilación en tiempo de ejecución utilizando las características de C # 6 requiere un nuevo compilador, como se menciona en @ thomas-levesque. Este compilador se puede instalar utilizando el paquete nuget https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/ .

Para aplicaciones de escritorio, hay un problema. El equipo de ASP.NET, en su sabiduría infinita, ha codificado la ruta del compilador como <runtime-directory>/bin/roslyn/csc.exe Consulte la discusión en https://github.com/dotnet/roslyn/issues/9483

Si su aplicación de escritorio está compilada en /myapp/app.exe , el compilador de Roslyn se ubicará en /myapp/roslyn/csc.exe , PERO THE CSharpCodeProvider csc.exe como /myapp/bin/roslyn/csc.exe

Por lo que sé, tienes dos opciones.

  1. Cree una rutina posterior a la construcción y / o instalación que moverá el subdirectorio /roslyn a /bin/roslyn .
  2. Corrige el código de tiempo de ejecución a través de la magia negra de reflexión.

Aquí está el # 2, exponiendo el CSharpCodeProvider como una propiedad en una clase de utilidad.

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; });


El proveedor de CodeDOM incorporado no es compatible con C # 6. Utilice este en su lugar:

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

Se basa en Roslyn y es compatible con las funciones de C # 6.

Solo cambia esta línea:

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

a esto:

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


Enfrenté el mismo problema del compilador completamente dañado y encontré una tercera solución además de las enumeradas en la respuesta de Aaron , al mirar la fuente descompilada de la biblioteca, encontré eso, antes de configurar la ruta codificada {ProgramLocation}/bin/roslyn it busca una variable de entorno (también codificada) para esa ubicación, y si está establecida, la utiliza en su lugar.

Con eso en mente, algunos códigos como este también "arreglarían" el problema:

//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

Si bien esto no recurre a la reflexión para entrometerse con lo interno, todavía se basa en los detalles de la implementación y el abuso de las variables de entorno como esto simplemente se siente mal. Personalmente me gusta esto más que la alternativa de reflexión, pero al mismo tiempo sé que ambos dependen de la implementación exacta (así como de la ruta codificada).

Debido a este problema, y ​​la necesidad de llamar a un programa externo para hacer lo que se debe hacer en el proceso, sigo considerando que esta biblioteca está completamente dañada.


Me encontré con este problema recientemente. Para el contexto, intentaba ejecutar un proyecto MSTest contra un proyecto de biblioteca utilizando System.CodeDom , pero siempre daba un compilador que implementaba C # 5 si tenía Microsoft.Net.Compilers o Microsoft.CodeDom.Providers.DotNetCompilerPlatform paquetes de referencia Por el proyecto bajo prueba.

Mi solución para esto fue:

  • Utilice el paquete Microsoft.CodeDom.Providers.DotNetCompilerPlatform
  • Configure el paquete PrivateAssets en PrivateAssets contentfiles;analyzers
  • Pase las opciones del proveedor con CompilerDirectoryPath establecido en el directorio copiado

El valor predeterminado para PrivateAssets es PrivateAssets contentfiles;analyzers;build , por lo que obtener proyectos de referencia para copiar también la carpeta requiere eliminar la build de la configuración.

Código de ejemplo:

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

Hacer que esto funcione con Microsoft.Net.Compilers sería un poco más tedioso ya que no se realiza ninguna copia, pero el paso final de señalar CompilerDirectoryPath en la carpeta de herramientas del paquete es el mismo.