I am creating types using TypeBuilder
. These types are then used as a arguments in a generic class. What I want to do is create the Type
from its name. The fact that the generic parameter is dynamic seems to be a barrier.
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();
}
}
Obviously I know how to create the Type
from MakeGenericType
, but in the real-life scenario I am working with, I don't want to (or can't) mangle the type name so that I can create the types separately and piece them together.
How can I recreate this kind of Type
from a string
name?
It occurred to me that I should use the version of Assembly.GetType()
that throws an Exception
on error. It threw a FileNotFoundException
, so apparently, in the generic arguments, only assemblies from file are allowed. To get around this, I registered for the AssemblyResolve
event from AppDomain
, and handled the case that DynamicAssembly
was not found on file. My working code:
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();
}