web-dev-qa-db-fra.com

Comment compiler un fichier C # avec Roslyn par programmation?

J'ai lu que vous ne pouvez pas compiler C # 6.0 avec CSharpCodeProvider et donc essayer de faire avec Roslyn. Mais je ne peux pas trouver un bon exemple comment charger un fichier, puis le compiler dans une DLL.

Comment dois-je écrire quelque chose de similaire à ce code avec Roslyn? Ou existe-t-il une autre façon de procéder? Maintenant, lorsque j'essaie de compiler des fichiers qui contiennent une référence à des projets avec du code C # 6.0, il suffit de dire "Le nom de type ou d'espace de noms 'x' n'existe pas dans l'espace de noms 'y' (vous manque-t-il une référence d'assembly?)"

    public string CompileCode()
    {
        var provider = new CSharpCodeProvider();
        var outputPath = Path.Combine(Path.GetDirectoryName(_path), $"Code.dll");
        var compilerparams = new CompilerParameters(_referencedAssemblies, outputPath);
        CompilerResults results = provider.CompileAssemblyFromFile(compilerparams, _path);
        var dllPath = results.PathToAssembly;
        if (!results.Errors.HasErrors)
            return dllPath;
        PrintError(results.Errors);
        return ""; 
    }

En résumé, je veux:

  • Charger un fichier C #
  • Compilez-le dans une DLL afin que je puisse le charger plus tard.
28
user1776562

J'ai créé un échantillon avec lequel vous pouvez travailler. Vous devez l'ajuster pour utiliser le temps d'exécution de .Net 4.6 afin que la version CSharp6 soit disponible pour vous. J'ai ajouté de petits détails pour que vous puissiez choisir les options de compilations.

Modifications requises - Modifiez le chemin d'exécution pour cibler .Net 4.6 Modifiez le LanguageVersion.Csharp5 à LanguageVersion.Csharp6 dans l'exemple ci-dessous.

 class Program
    {
        private static readonly IEnumerable<string> DefaultNamespaces =
            new[]
            {
                "System", 
                "System.IO", 
                "System.Net", 
                "System.Linq", 
                "System.Text", 
                "System.Text.RegularExpressions", 
                "System.Collections.Generic"
            };

        private static string runtimePath = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\{0}.dll";

        private static readonly IEnumerable<MetadataReference> DefaultReferences =
            new[]
            {
                MetadataReference.CreateFromFile(string.Format(runtimePath, "mscorlib")),
                MetadataReference.CreateFromFile(string.Format(runtimePath, "System")),
                MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Core"))
            };

        private static readonly CSharpCompilationOptions DefaultCompilationOptions =
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
                    .WithOverflowChecks(true).WithOptimizationLevel(OptimizationLevel.Release)
                    .WithUsings(DefaultNamespaces);

        public static SyntaxTree Parse(string text, string filename = "", CSharpParseOptions options = null)
        {
            var stringText = SourceText.From(text, Encoding.UTF8);
            return SyntaxFactory.ParseSyntaxTree(stringText, options, filename);
        }

        static void Main(string[] args)
        {
            var fileToCompile = @"C:\Users\DesktopHome\Documents\Visual Studio 2013\Projects\ConsoleForEverything\SignalR_Everything\Program.cs";
            var source = File.ReadAllText(fileToCompile);
            var parsedSyntaxTree = Parse(source, "", CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5));

            var compilation
                = CSharpCompilation.Create("Test.dll", new SyntaxTree[] { parsedSyntaxTree }, DefaultReferences, DefaultCompilationOptions);
            try
            {
                var result = compilation.Emit(@"c:\temp\Test.dll");

                Console.WriteLine(result.Success ? "Sucess!!" : "Failed");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            Console.Read();
        }

Cela nécessiterait de petits ajustements, mais cela devrait vous donner les résultats souhaités. Modifiez-le comme vous le souhaitez.

31
vendettamit

Vous devez utiliser le package NuGet Microsoft.CodeAnalysis.CSharp.

var syntaxTree = CSharpSyntaxTree.ParseText(source);

CSharpCompilation compilation = CSharpCompilation.Create(
    "assemblyName",
    new[] { syntaxTree },
    new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) },
    new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

using (var dllStream = new MemoryStream())
using (var pdbStream = new MemoryStream())
{
    var emitResult = compilation.Emit(dllStream, pdbStream);
    if (!emitResult.Success)
    {
        // emitResult.Diagnostics
    }
}
11
meziantou