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.
- Cree una rutina posterior a la construcción y / o instalación que moverá el subdirectorio
/roslyn
a/bin/roslyn
. - 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
enPrivateAssets
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.