2010-05-13 1 views
16

Sto cercando di capire se è possibile generare dinamicamente gli assiemi, fare riferimento a un tipo in un assieme generato dinamicamente in precedenza.C# - Riferimento a un tipo in un assieme generato dinamicamente

Ad esempio:

using System; 
using System.CodeDom.Compiler; 
using System.Reflection; 
using Microsoft.CSharp; 

CodeDomProvider provider = new CSharpCodeProvider(); 
CompilerParameters parameters = new CompilerParameters(); 

parameters.GenerateInMemory = true; 

CompilerResults results = provider.CompileAssemblyFromSource(parameters, @" 
namespace Dynamic 
{ 
    public class A 
    { 
    } 
} 
"); 

Assembly assem = results.CompiledAssembly; 

CodeDomProvider provider2 = new CSharpCodeProvider(); 
CompilerParameters parameters2 = new CompilerParameters(); 

parameters2.ReferencedAssemblies.Add(assem.FullName); 
parameters2.GenerateInMemory = true; 

CompilerResults results2 = provider2.CompileAssemblyFromSource(parameters2, @" 
namespace Dynamic 
{ 
    public class B : A 
    { 
    } 
} 
"); 

if (results2.Errors.HasErrors) 
{ 
    foreach (CompilerError error in results2.Errors) 
    { 
     Console.WriteLine(error.ErrorText); 
    } 
} 
else 
{ 
    Assembly assem2 = results2.CompiledAssembly; 
} 

Questo codice stampa il seguente sulla console: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?)

ho provato un sacco di modi diversi, ma nulla sembra funzionare. Mi sto perdendo qualcosa? È possibile?

EDIT: Risolvere il bug nel codice fornisce questo errore invece: Metadata file 'l0livsmn, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' could not be found

EDIT2: un po 'di una nota a margine, ma cambiando GenerateInMemory false, e facendo parameters2.ReferencedAssemblies.Add(assem.Location); causerà a compilare correttamente, ma io' Preferisco di gran lunga fare riferimento all'assembly che è direttamente in memoria piuttosto che emettere file temporanei.

risposta

4

Penso che in

CompilerResults results2 = provider2.CompileAssemblyFromSource(parameters, @" 
namespace Dynamic 
{ 
    public class B : A 
    { 
    } 
} 
"); 

Si vuole passare parameters2, non parameters.

Ho trovato il modo per farlo, è necessario NON compilare il primo in memoria, se non lo si fa, creerà una DLL per questo assembly nella directory temporanea, inoltre, nella chiamata a

ReferencedAssemblies.Add() 

tu non passare il nome di montaggio, si passa il percorso di montaggio, dare un'occhiata a questo codice, dovrebbe funzionare senza problemi:

 CodeDomProvider provider = new CSharpCodeProvider(); 
     CompilerParameters parameters = new CompilerParameters();    

     CompilerResults results = provider.CompileAssemblyFromSource(parameters, @" 
      namespace Dynamic 
      { 
       public class A 
       { 
       } 
      } 
      "); 

     Assembly assem = results.CompiledAssembly; 

     CodeDomProvider provider2 = new CSharpCodeProvider(); 
     CompilerParameters parameters2 = new CompilerParameters(); 

     parameters2.ReferencedAssemblies.Add(assem.Location); 
     parameters2.GenerateInMemory = true; 

     CompilerResults results2 = provider2.CompileAssemblyFromSource(parameters2, @" 
      namespace Dynamic 
      { 
       public class B : A 
       { 
       } 
      } 
      "); 

     if (results2.Errors.HasErrors) 
     { 
      foreach (CompilerError error in results2.Errors) 
      { 
       Console.WriteLine(error.ErrorText); 
      } 
     } 
     else 
     { 
      Assembly assem2 = results2.CompiledAssembly; 
     } 
+0

Ah, spara. Grazie! L'ho riparato. Vedi la modifica. – Ashley

+0

Vedere la mia seconda modifica. Penso che lo abbiamo capito all'incirca alla stessa ora. Mi piacerebbe comunque poter fare riferimento all'assembly in memoria, se possibile. – Ashley

+0

Sembra che il codice sorgente venga eseguito e creato il secondo assembly. Ma se provi a caricare i tipi risiedi nel secondo assembly (usando assem2.GetTypes()), riceverai una ReflectionTypeLoadException –

2

MSDN dice che si può:

Restrizioni Tipo Riferimenti

Assiemi possono fare riferimento a tipi definiti in un altro assembly. Un assembly dinamico temporaneo può fare riferimento in modo sicuro ai tipi definiti in un altro gruppo dinamico transitorio , un assembly dinamico persistente o un assieme statico . Tuttavia, il comune runtime linguaggio non consente un modulo dinamico persistente a , riferimento a un tipo definito in un modulo dinamico transitorio . Questo è perché quando il modulo dinamico persistente viene caricato dopo essere stato salvato nel disco , il runtime non può risolvere i riferimenti ai tipi definiti nel modulo dinamico transitorio .

+2

Bene, suppongo che la domanda ora sia: "Come faccio a fare riferimento all'assembly dinamico transitorio in memoria?" – Ashley

+0

Mi chiedo: l'assembly viene creato in memoria, ma viene aggiunto all'applicazione ApplicationDomain per impostazione predefinita? O lo caricheresti tu stesso? Oppure chiama 'AppDomain.DefineDynamicAssembly'? –

+0

Hmm, questa è una buona domanda. Ho provato a giocarci un po 'e l'assembly generato dinamicamente sembra essere stato caricato. – Ashley