2010-05-13 5 views
16

J'essaie de déterminer s'il est possible, lorsque vous générez dynamiquement des assemblages, de référencer un type dans un assemblage précédemment généré dynamiquement.C# - Référencer un type dans un assemblage généré dynamiquement

Par exemple:

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

Ce code imprime ce qui suit sur la console: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?)

Je l'ai essayé beaucoup de façons différentes, mais rien ne semble fonctionner. Est-ce que je manque quelque chose? Est-ce seulement possible?

EDIT: Fixation du bug dans le code fournit cette erreur à la place: Metadata file 'l0livsmn, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' could not be found

EDIT2: Un peu d'une note de côté, mais en changeant GenerateInMemory false et faire parameters2.ReferencedAssemblies.Add(assem.Location); le fera compiler correctement, mais je d préfèrent grandement faire référence à l'ensemble qui est directement en mémoire plutôt que de sortir des fichiers temporaires.

Répondre

4

Je pense que dans

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

Vous voulez passer parameters2, pas parameters.

J'ai trouvé le moyen de le faire, vous ne devez pas compiler le premier en mémoire, si vous ne le faites pas, il va créer une DLL pour cet assembly dans votre répertoire temp, plus, dans votre appel à

ReferencedAssemblies.Add() 

vous ne passez le nom de montage, vous passez le chemin d'assemblage, jetez un oeil à ce code, il devrait fonctionner parfaitement:

 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, tirer. Merci! Je l'ai corrigé. Voir l'édition. – Ashley

+0

Voir ma deuxième édition. Je pense que nous l'avons compris à peu près en même temps. J'aimerais quand même pouvoir référencer l'assemblage en mémoire, si possible. – Ashley

+0

Il semble que le code source s'exécute et crée le second assembly. Mais si vous essayez de charger les types résident dans le second assembly (en utilisant assem2.GetTypes()), vous obtiendrez une ReflectionTypeLoadException –

2

MSDN dit, vous pouvez:

Restrictions sur Type Références

assemblées peuvent faire référence à des types définis dans un autre assemblage. Un ensemble dynamique transitoire peut référencer en toute sécurité les types définis dans un autre ensemble dynamique transitoire , un ensemble dynamique ou un ensemble statique . Cependant, l'exécution courante de la langue ne permet pas à un module dynamique persistante de référencer un type défini dans un module dynamique transitoire . Ceci est parce que lorsque le module dynamique persisté est chargé après avoir été enregistré sur le disque , le moteur d'exécution ne peut pas résoudre les références aux types définis dans le module dynamique transitoire .

+2

Eh bien, je suppose que la question est maintenant, "Comment puis-je référencer l'assemblage dynamique transitoire en mémoire?" – Ashley

+0

Je me demande: l'assembly est créé en mémoire, mais est-il ajouté à l'ApplicationDomain par défaut? Ou voulez-vous le charger vous-même? Ou appelez 'AppDomain.DefineDynamicAssembly'? –

+0

Hmm, c'est une bonne question. J'ai essayé de jouer avec un peu, et l'assemblage généré dynamiquement semble définitivement être chargé. – Ashley

Questions connexes