2012-05-25 53 views
7

Estoy generando un Greeter.dll utilizando el compilador de Roslyn. Mi problema ocurre al tratar de cargar el archivo DLL.Cargando un ensamblado generado por el compilador de Roslyn

Aquí está el código:

mensaje
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("<ENTER> to continue"); 
      Console.ReadLine(); 

     } 
    } 
    // Thanks, http://blogs.msdn.com/b/csharpfaq/archive/2011/11/23/using-the-roslyn-symbol-api.aspx 
} 

El error se produce en la línea assembly = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), @"Greeter.dll")); y lee

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

que se podría traducir

un manifiesto de ensamblado se espera que en el módulo.

¿Alguien sabe lo que me falta aquí?

+0

tiene varios errores en su código. Aparentemente, ya los descubriste (pero necesitar un PDB no estaba entre ellos). La próxima vez, mira 'result.Diagnostics' para descubrir cuál es el problema. – svick

Respuesta

0

he estado añadiendo soporte Roslyn a la O2 Plarform y aquí es cómo se puede utilizar su apoyo Roslyn para compilar (código), crear (y montaje) y invocar (su método) una línea de código:

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 

Aquí está una versión que ejecuta un fragmento de código que se parece a la suya (he añadido un valor de retorno):

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 

por un par más detalles y capturas de pantalla de lo que esto parece, consulte esta entrada del blog: 1 line to compile, create and execute: O2 Script to use Roslyn to Dynamically compile and execute a method

ACTUALIZACIÓN: ver http://blog.diniscruz.com/search/label/Roslyn para un número gran número de publicaciones y herramientas relacionadas Roslyn (creada usando la Plataforma O2)

-1

Resulta que necesitaba crear un archivo 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); 
} 
+0

Ese no es el problema en su código. – svick

0

Este código funcionaba muy bien:

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("<ENTER> 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 
} 
+2

Solo una pieza de código sin explicación no es muy útil. ¿Esto significa que resolvió su problema? ¿O se supone que es solo una extensión de la pregunta? – svick

+0

Tenga en cuenta que en CompilationsOptions, AssemblyKind se renombró a: OutputKind.DynamicallyLinkedLibrary –

+0

Como referencia, uno de los problemas con el código original fue la definición de OutputKind (ya que uno de los errores era la necesidad de tener un método principal estático) –

13

Me encontré con esto y, aunque usted tiene una respuesta aceptada, no creo que sea útil en general. Entonces, dejaré esto aquí para futuros buscadores como yo.

El problema con el código es dos cosas, que le han descubierto observando el valor devuelto por

EmitResult result = compilation.Emit(file); 

Si nos fijamos en las propiedades del objeto EmitResult, se habría encontrado que hay hubo 2 errores en los resultados. Miembro de Diagnóstico.

  1. método principal no encontró
  2. No se pudo encontrar la consola de clase

Por lo tanto, para solucionar el problema, 1. Es necesario marcar el resultado como un archivo DLL 2.Necesita agregar 'using System;' al código que está pasando en el API o decir 'System.Console.WriteLine'

El código siguiente funciona haciendo cambios para corregir esas dos cuestiones:

 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("<ENTER> to continue"); 
     Console.ReadLine(); 
0

hay una nueva API para las Referencias que tiene este aspecto:

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

esto es con la última Roslyn-CTP 2012 en septiembre ...

Cuestiones relacionadas