Caricamento di un assieme generato dal compilatore di Roslyn

Sto generando un Greeter.dll utilizzando il compilatore di Roslyn. Il mio problema si verifica cercando di caricare il file DLL.

Ecco il codice:

using System; using Roslyn.Compilers; using Roslyn.Compilers.CSharp; using System.IO; using System.Reflection; using System.Linq; namespace LoadingAClass { class Program { static void Main(string[] args) { var syntaxTree = SyntaxTree.ParseCompilationUnit(@" class Greeter { static void Greet() { Console.WriteLine(""Hello, World""); } }"); var compilation = Compilation.Create("Greeter.dll", syntaxTrees: new[] { syntaxTree }, references: new[] { new AssemblyFileReference(typeof(object).Assembly.Location), new AssemblyFileReference(typeof(Enumerable).Assembly.Location), }); Assembly assembly; using (var file = new FileStream("Greeter.dll", FileMode.Create)) { EmitResult result = compilation.Emit(file); } assembly = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), @"Greeter.dll")); Type type = assembly.GetType("Greeter"); var obj = Activator.CreateInstance(type); type.InvokeMember("Greet", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, null); Console.WriteLine(" to continue"); Console.ReadLine(); } } // Thanks, http://blogs.msdn.com/b/csharpfaq/archive/2011/11/23/using-the-roslyn-symbol-api.aspx } 

Il messaggio di errore si verifica sull’assembly di riga assembly = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), @"Greeter.dll")); e legge

Im Modul wurde ein Assemblymanifest erwartet. (Ausnahme von HRESULT: 0x80131018)

Che si traduce approssimativamente a

Un modulo di assemblaggio era previsto nel modulo.

Qualcuno sa cosa mi manca qui?

Ho aggiunto il supporto di Roslyn alla O2 Plarform ed ecco come si può usare il suo supporto Roslyn per compilare (codice), creare (e assemblare) e invocare (il suo metodo) una riga di codice:

 return @"using System; class Greeter { static string Greet() { return ""Another hello!!""; }}" .tree().compiler("Great").create_Assembly().type("Greeter").invokeStatic("Greet"); //O2Ref:O2_FluentSharp_Roslyn.dll 

Ecco una versione che esegue uno snippet di codice simile al tuo (ho aggiunto un valore di ritorno):

 panel.clear().add_ConsoleOut(); var code = @" using System; class Greeter { static string Greet() { Console.WriteLine(""Hello, World""); return ""hello from here""; } }"; var tree = code.astTree(); if (tree.hasErrors()) return tree.errors(); var compiler = tree.compiler("Great") .add_Reference("mscorlib"); if (compiler.hasErrors()) return compiler.errors(); var assembly =tree.compiler("Great") .create_Assembly(); return assembly.type("Greeter") .invokeStatic("Greet"); //O2Ref:O2_FluentSharp_Roslyn.dll //O2File:_Extra_methods_Roslyn_API.cs //O2File:API_ConsoleOut.cs 

Per un paio di altri dettagli e schermate di come appare, vedi questo post del blog: 1 riga per compilare, creare ed eseguire: O2 Script per utilizzare Roslyn per compilare ed eseguire dynamicmente un metodo

AGGIORNAMENTO: consultare http://blog.diniscruz.com/search/label/Roslyn per un numero elevato di post e strumenti relativi a Roslyn (creati utilizzando la piattaforma O2)

Mi sono imbattuto in questo e, anche se hai una risposta accettata, non penso sia di aiuto in generale. Quindi, lascerò questo qui per futuri ricercatori come me.

Il problema con il codice è due cose, che avresti scoperto osservando il valore restituito da

 EmitResult result = compilation.Emit(file); 

Se si guardano le proprietà sull’object EmitResult, si sarebbe scoperto che c’erano 2 errori nel membro Result.Diagnostics.

  1. Metodo principale non trovato
  2. Imansible trovare la Console di class

Quindi, per risolvere il problema, 1. È necessario contrassegnare l’output come dll 2. È necessario aggiungere ‘using System;’ al codice che stai passando nell’API o dì “System.Console.WriteLine”

Il seguente codice funziona modificando per correggere questi due problemi:

  var outputFile = "Greeter.dll"; var syntaxTree = SyntaxTree.ParseCompilationUnit(@" // ADDED THE FOLLOWING LINE using System; class Greeter { public void Greet() { Console.WriteLine(""Hello, World""); } }"); var compilation = Compilation.Create(outputFile, syntaxTrees: new[] { syntaxTree }, references: new[] { new AssemblyFileReference(typeof(object).Assembly.Location), new AssemblyFileReference(typeof(Enumerable).Assembly.Location), }, // ADDED THE FOLLOWING LINE options: new CompilationOptions(OutputKind.DynamicallyLinkedLibrary)); using (var file = new FileStream(outputFile, FileMode.Create)) { EmitResult result = compilation.Emit(file); } Assembly assembly = Assembly.LoadFrom("Greeter.dll"); Type type = assembly.GetType("Greeter"); var obj = Activator.CreateInstance(type); type.InvokeMember("Greet", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, null); Console.WriteLine(" to continue"); Console.ReadLine(); 

Questo codice ha funzionato magnificamente:

 using System; using Roslyn.Compilers; using Roslyn.Compilers.CSharp; using System.IO; using System.Reflection; using System.Linq; namespace LoadingAClass { class Program { static void Main(string[] args) { var syntaxTree = SyntaxTree.ParseCompilationUnit(@" using System; namespace HelloWorld { class Greeter { public static void Greet() { Console.WriteLine(""Hello, World""); } } }"); string dllPath = Path.Combine(Directory.GetCurrentDirectory(), "Greeter.dll"); string pdbPath = Path.Combine(Directory.GetCurrentDirectory(), "Greeter.pdb"); var compilation = Compilation.Create(dllPath, new CompilationOptions( assemblyKind: AssemblyKind.DynamicallyLinkedLibrary )) .AddSyntaxTrees( syntaxTree ) .AddReferences(new AssemblyFileReference(typeof(object).Assembly.Location)) .AddReferences(new AssemblyFileReference(typeof(Enumerable).Assembly.Location)); EmitResult result; using (FileStream dllStream = new FileStream(dllPath, FileMode.OpenOrCreate)) using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate)) { result = compilation.Emit( executableStream: dllStream, pdbFileName: pdbPath, pdbStream: pdbStream); } if (result.Success) { //assembly = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), @"Greeter.dll")); Assembly assembly = Assembly.LoadFrom(@"Greeter.dll"); Type type = assembly.GetType("HelloWorld.Greeter"); var obj = Activator.CreateInstance(type); type.InvokeMember("Greet", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, null); } else { Console.WriteLine("No Go"); Console.WriteLine(result.Diagnostics.ToString()); } Console.WriteLine(" to continue"); Console.ReadLine(); } } // Thanks, http://blogs.msdn.com/b/csharpfaq/archive/2011/11/23/using-the-roslyn-symbol-api.aspx // Thanks, http://social.msdn.microsoft.com/Forums/en-US/roslyn/thread/d620a4a1-3a90-401b-b946-bfa1fc6ad7a2 } 

C’è una nuova API per i riferimenti che assomiglia a questo:

 var compilation = Compilation.Create(outputFile, syntaxTrees: new[] { syntaxTree }, references: new[] { new MetadataFileReference(typeof(object).Assembly.Location), new MetadataFileReference(typeof(Enumerable).Assembly.Location), }, options: new CompilationOptions(OutputKind.DynamicallyLinkedLibrary) ); 

Questo è con l’ultimo Roslyn-CTP 2012 in settembre …

Ho scoperto che avevo bisogno di creare un file pdb.

 using (FileStream dllStream = new FileStream(dllPath, FileMode.OpenOrCreate)) using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate)) { result = compilation.Emit( executableStream: dllStream, pdbFileName: pdbPath, pdbStream: pdbStream); }