CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" );
CompilerParameters objCompilerParameters = new CompilerParameters();
...
CompilerResults objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );
Lorsque je compile mes fichiers, j'obtiens:
FileFunctions.cs (347): Erreur: caractère inattendu '$'
Est-ce que quelqu'un sait comment faire fonctionner l'interpolation de chaînes avec la compilation CodeDom?
J'ai trouvé ce lien: Comment cibler .net 4.5 avec CSharpCodeProvider?
J'ai donc essayé:
var providerOptions = new Dictionary<string, string>();
providerOptions.Add( "CompilerVersion", "v4.0" );
// Instantiate the compiler.
CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp", providerOptions );
Mais je reçois toujours la même erreur.
J'ai également mis à jour le framework cible vers .NET Framework 4.6.
REMARQUE: je ne peux pas spécifier "v4.5" ou "v4.6" ou j'obtiendrai:
************** 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)
J'ai essayé d'utiliser la suggestion de Thomas Levesque:
CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
Mais alors je reçois:
************** 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)
Je ne sais pas pourquoi il essaie de rechercher "csc.exe" dans un sous-dossier de mon répertoire bin.
Ce chemin existe:
C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC #\bin\x86\Debug\roslyn
Mais il cherchait:
C:\Users\Derek.Morin\Documents\Visual Studio 2010\Projects\ScriptCode\ScriptCode.ConvertedToC #\bin\x86\Debug\bin\roslyn\csc.exe
Le fournisseur CodeDOM intégré ne prend pas en charge C # 6. Utilisez celui-ci à la place:
https://www.nuget.org/packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/
Il est basé sur Roslyn et prend en charge les fonctionnalités C # 6.
Modifiez simplement cette ligne:
CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp" );
pour ça:
CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
Mise à jour: mars 2018
Attention, NuGet version 1.0.6 ... 1.0.8 ne copiera pas le dossier/roslyn dans le répertoire de sortie de la génération sur les projets non Web. Meilleur bâton avec 1.0.5 https://github.com/aspnet/RoslynCodeDomProvider/issues/38
La compilation au moment de l'exécution à l'aide des fonctionnalités C # 6 nécessite un nouveau compilateur, comme l'a mentionné @ thomas-levesque. Ce compilateur peut être installé à l'aide du package nuget Microsoft.CodeDom.Providers.DotNetCompilerPlatform
.
Pour les applications de bureau, il y a un problème. L'équipe ASP.NET, dans sa sagesse infinie, a codé en dur le chemin vers le compilateur comme <runtime-directory>\bin\roslyn\csc.exe
Voir la discussion sur https://github.com/dotnet/roslyn/issues/948
Si votre application de bureau est compilée en \myapp\app.exe
, le compilateur roslyn sera situé à \myapp\roslyn\csc.exe
, MAIS LE CSharpCodeProvider
RESOLURA csc.exe
comme \myapp\bin\roslyn\csc.exe
Autant que je sache, vous avez deux options
\roslyn
sous-répertoire de \bin\roslyn
.Voici # 2, en exposant le CSharpCodeProvider
comme une propriété dans une classe utilitaire.
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;
});
J'ai récemment abordé ce problème. Pour le contexte, j'essayais d'exécuter un projet MSTest sur un projet de bibliothèque en utilisant System.CodeDom
, mais cela donnait toujours un compilateur qui implémentait C # 5, que j'aie ou non Microsoft.Net.Compilers
ou Microsoft.CodeDom.Providers.DotNetCompilerPlatform
packages référencés par le projet sous test.
Ma solution pour cela était:
Microsoft.CodeDom.Providers.DotNetCompilerPlatform
PrivateAssets
sur contentfiles;analyzers
CompilerDirectoryPath
défini sur le répertoire copiévaleur par défaut pour PrivateAssets
est contentfiles;analyzers;build
, donc obtenir des projets de référencement pour copier également le dossier nécessite de supprimer build
du paramètre.
Exemple de code:
var compiler = CodeDomProvider.CreateProvider("cs", new Dictionary<string, string> {
{ "CompilerDirectoryPath", Path.Combine(Environment.CurrentDirectory, "roslyn") }
});
Faire fonctionner cela avec Microsoft.Net.Compilers
serait un peu plus fastidieux car aucune copie n'est effectuée, mais l'étape finale de pointage de CompilerDirectoryPath
vers le dossier tools du package est la même.
Informations mises à jour: même après la publication de FW 4.8, vous ne pouvez toujours pas utiliser toutes les nouvelles fonctionnalités de C # 8.0 - la distribution contient CSC, limitée à la version 5.0; Mais il y a un hack pour utiliser CSC, distribué avec VS2019 (oui, vous devez l'installer):
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
BTW malgré l'option explicite 'GenerateInMemory', votre code sera quand même écrit dans le fichier et alors seulement sera compilé. Gardez à l'esprit si vous souhaitez que votre application s'exécute sans accès au disque.
Face au même problème du compilateur complètement cassé et trouvé une troisième solution en plus de celles répertoriées dans le réponse d'Aaron , en regardant la source décompilée de la bibliothèque, j'ai trouvé que, avant de définir le chemin codé en dur {ProgramLocation}\bin\roslyn
il recherche une variable d'environnement (également codée en dur) pour cet emplacement, et s'il est défini, il l'utilise à la place.
Dans cet esprit, un code comme celui-ci "résoudrait" également le problème:
//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
Bien que cela ne recourt pas à la réflexion pour jouer avec les éléments internes, cela dépend toujours des détails de mise en œuvre et abuser des variables d'environnement comme celle-ci semble tout simplement faux. Personnellement, j'aime plus que l'alternative de réflexion, mais en même temps, je sais que les deux s'appuient sur la mise en œuvre exacte (ainsi que sur le chemin codé en dur).
En raison de ce problème et de la nécessité d'appeler un programme externe pour faire ce qui devrait être fait en cours de processus, je considère toujours que cette bibliothèque est complètement endommagée.