Utilisation des fonctionnalités C# 6 avec CodeDomProvider (rosyln)

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

CompilerParameters objCompilerParameters = new CompilerParameters();

...

CompilerResults objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );

quand je compile mes fichiers j'obtiens:

FileFunctions.cs (347): erreur: caractère inattendu '$'

est-ce que quelqu'un sait comment obtenir l'interpolation de chaîne de travail avec la compilation CodeDom?

j'ai trouvé ce lien: comment cibler .net 4.5 avec CSharpCodeProvider?

donc j'ai essayé:

     var providerOptions = new Dictionary<string, string>();
     providerOptions.Add( "CompilerVersion", "v4.0" );

     // Instantiate the compiler.
     CodeDomProvider objCodeCompiler = CodeDomProvider.CreateProvider( "CSharp", providerOptions );

mais je continue obtenir la même erreur.

j'ai également mis à jour le cadre cible en .net cadre 4.6.

NOTE: je ne peux pas spécifier "v4.5" ou "v4.6" ou je vais obtenir:

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

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

Je ne sais pas pourquoi il cherche" csc.exe" dans un sous-dossier de mon répertoire bin.

Ce chemin existe:

C:UsersDerek.MorinDocumentsVisual Studio 2010ProjectsScriptCodeScriptCode.ConvertedToC#binx86Debugroslyn

mais il cherchait:

C:UsersDerek.MorinDocumentsVisual Studio 2010ProjectsScriptCodeScriptCode.ConvertedToC#binx86Debugbinroslyncsc.exe

25
demandé sur Community 2015-07-26 20:00:21

4 réponses

le fournisseur de code intégré ne supporte pas C# 6. Utilisez plutôt celle-ci:

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

est basé sur Roslyn et supporte les fonctionnalités C# 6.

il suffit de changer cette ligne:

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

à ceci:

CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
18
répondu Thomas Levesque 2015-07-26 20:26:34

Mise À Jour: Mars 2018

mise en garde, NuGet Version 1.0.6 ... 1.0.8 va ne pas copier le dossier / roslyn dans le répertoire de sortie de build sur non-web projet. Meilleur bâton avec 1.0.5 https://github.com/aspnet/RoslynCodeDomProvider/issues/38

La compilation

avec les fonctionnalités C#6 nécessite un nouveau compilateur, comme @thomas-levesque l'a mentionné. Ce compilateur peut être installé en utilisant le paquet nuget Microsoft.CodeDom.Providers.DotNetCompilerPlatform .

pour les applications bureautiques, il y a un problème. Les ASP.NET équipe, dans leur sagesse infinie ont codé dur le chemin vers le compilateur comme <runtime-directory>\bin\roslyn\csc.exe voir la discussion à https://github.com/dotnet/roslyn/issues/9483

si votre application de bureau est compilée en \myapp\app.exe , le compilateur roslyn sera situé à \myapp\roslyn\csc.exe , mais le CSharpCodeProvider résoudra csc.exe comme \myapp\bin\roslyn\csc.exe

"

autant que je sache, vous avez deux options

  1. créez une routine de post-construction et/ou d'installation qui déplacera le sous-répertoire \roslyn à \bin\roslyn .
  2. fixez le code runtime par magie noire de réflexion.

voici #2, en exposant le CSharpCodeProvider en tant que 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;
});
22
répondu Aaron Hudon 2018-03-16 19:51:26

fait face à la même question du compilateur complètement cassé et a trouvé une troisième solution en plus de ceux énumérés dans la réponse D'Aaron , en regardant la source décomposée de la bibliothèque, j'ai trouvé que, avant de définir le chemin hardcodé {ProgramLocation}\bin\roslyn il recherche une variable d'environnement (aussi hardcodé) pour cet endroit, et si elle est définie, il utilise à la place.

avec cela à l'esprit, un code comme celui - ci pourrait aussi" corriger " 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 n'ait pas recours à la réflexion pour brouiller les internes, cela repose toujours sur des détails d'implémentation et abuser de variables d'environnement comme cela semble tout simplement mal. J'aime personnellement cela plus que l'alternative de réflexion, mais en même temps je sais que les deux repose sur la mise en œuvre exacte (ainsi que le chemin codé).

en Raison de ce problème, et la nécessité d'appeler un programme externe pour faire ce qui devrait être fait en cours de route, je considère toujours cette bibliothèque comme complètement cassée.

0
répondu Alejandro 2018-03-23 15:31:40

a rencontré ce problème récemment. Pour le contexte, j'essayais d'exécuter un projet MSTest contre un projet de bibliothèque en utilisant System.CodeDom , mais il donnait toujours un compilateur qui implémentait C# 5 que j'aie ou non des paquets Microsoft.Net.Compilers ou Microsoft.CodeDom.Providers.DotNetCompilerPlatform référencés par le projet à l'essai.

ma solution pour cela était:

  • utiliser le paquet Microsoft.CodeDom.Providers.DotNetCompilerPlatform
  • Ensemble PrivateAssets à contentfiles;analyzers
  • Pass options de fournisseur avec CompilerDirectoryPath ensemble pour le répertoire copié

la valeur par défaut pour PrivateAssets est contentfiles;analyzers;build , donc obtenir des projets de référencement pour copier aussi 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 ça avec Microsoft.Net.Compilers serait un peu plus fastidieux comme aucune copie n'est faite, mais l'étape finale de pointage CompilerDirectoryPath vers le dossier Outils Du paquet est la même.

0
répondu tychon 2018-09-29 22:41:45