2017-04-06 2 views
0

Je crée des types en utilisant TypeBuilder. Ces types sont ensuite utilisés comme arguments dans une classe générique. Ce que je veux faire est de créer le Type à partir de son nom. Le fait que le paramètre générique soit dynamique semble être un obstacle.Récupérer Type Foo <Bar> à partir du nom lorsque Bar est créé à partir de TypeBuilder

static public class DynamicTypeTest 
{ 
    public class Generic<T> { } 

    static public void Test() 
    { 
     Type dynamicType = createDynamicType(); 
     Type genericType = typeof(Generic<>); 

     // Generic<DynamicType> 
     Type genericDynamicType = genericType.MakeGenericType(new Type[]{dynamicType}); 

     Debug.Assert(TypeFromName(genericDynamicType.FullName) == genericDynamicType);    // fail 
     Debug.Assert(TypeFromName(genericDynamicType.AssemblyQualifiedName) == genericDynamicType); // fail 
     Debug.Assert(TypeFromName(genericDynamicType.Name) == genericDynamicType);     // fail 

     // Generic<int> 
     Type genericIntType = genericType.MakeGenericType(new Type[] { typeof(int) }); 

     Debug.Assert(TypeFromName(genericIntType.FullName) == genericIntType); // This succeeds. Replacing 'int' with a Type defined in another project also works 
    } 

    // This is the essence of what I want to do 
    static private Type TypeFromName(string name) 
    { 
     return Assembly.GetExecutingAssembly().GetType(name); 
    } 

    static private Type createDynamicType() 
    { 
     AssemblyName assemblyName = new AssemblyName("DynamicAssembly"); 
     AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 
     ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule"); 
     TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass; 
     TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicType", typeAttributes, typeof(System.Object)); 

     return typeBuilder.CreateType(); 
    } 
} 

Il est évident que je sais comment créer le Type de MakeGenericType, mais dans le scénario de la vie réelle, je travaille avec, je ne veux pas (ou ne peut pas) mutiler le nom du type afin que je puisse créer les types séparément et les assembler.

Comment puis-je recréer ce type de Type à partir d'un nom string?

+1

Eh bien, votre type généré réside dans l'assembly que vous avez appelé 'DynamicAssembly', n'est-ce pas? Alors pourquoi le cherchez-vous dans l'assemblage _executing_? –

+0

'Generic <>' vit dans l'assembly d'exécution. Récupérer également 'Generic ' de l'exécution des travaux d'assemblage. (Récupérer 'Generic ' de 'DynamicAssembly' ne fonctionne pas - J'ai essayé.) – AbleArcher

+0

Récupérer' DynamicType' de 'DynamicAssembly' et' Generic <> 'de' ExecutingAssembly' (ou simplement 'typeof' si vous connaissez 'Generic <>' statiquement). Puis les assembler en utilisant 'MakeGenericType'. –

Répondre

0

Il m'est apparu que je devrais utiliser la version de Assembly.GetType() qui jette un Exception en erreur. Il a jeté un FileNotFoundException, donc apparemment, dans les arguments génériques, seuls les assemblys à partir du fichier sont autorisés. Pour contourner ce problème, je me suis inscrit à l'événement AssemblyResolve de AppDomain, et pris en charge le cas où DynamicAssembly n'a pas été trouvé dans le fichier. Mon code de travail:

static public class DynamicTypeTest 
{ 
    public class Generic<T> { } 

    static public void Test() 
    { 
     AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; 

     Type dynamicType = createDynamicType(); 
     Type genericType = typeof(Generic<>); 

     // Generic<DynamicType> 
     Type genericDynamicType = genericType.MakeGenericType(new Type[]{dynamicType}); 

     Debug.Assert(TypeFromName(genericDynamicType.FullName) == genericDynamicType); // pass 

     AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve; 
    } 

    static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
    { 
     foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) 
     { 
      AssemblyName assemblyName = assembly.GetName(); 

      if (args.Name == assemblyName.FullName) 
      { 
       return assembly; 
      } 
     } 

     return null; 
    } 

    // This is the essence of what I want to do 
    static private Type TypeFromName(string name) 
    { 
     try 
     { 
      return typeof(Generic<>).Assembly.GetType(name, true); 
     } 
     catch (Exception) 
     { 
      return null; 
     } 
    } 

    static private Type createDynamicType() 
    { 
     AssemblyName assemblyName = new AssemblyName("DynamicAssembly"); 
     AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 
     ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule"); 
     TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass; 
     TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicType", typeAttributes, typeof(System.Object)); 

     return typeBuilder.CreateType(); 
    }