从 TypeBuilder 创建 Bar 时从名称中检索类型 Foo<Bar>
Retrieve Type Foo<Bar> from name when Bar is created from TypeBuilder
我正在使用 TypeBuilder
创建类型。然后将这些类型用作泛型 class 中的参数。我想要做的是从它的名字创建 Type
。通用参数是动态的这一事实似乎是一个障碍。
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();
}
}
显然我知道如何从 MakeGenericType
创建 Type
,但在我正在处理的现实场景中,我不想(或不能)破坏键入名称,以便我可以单独创建类型并将它们拼凑在一起。
如何从 string
名称重新创建这种 Type
?
我突然想到我应该使用 Assembly.GetType()
的版本,它会在错误时抛出 Exception
。它抛出一个 FileNotFoundException
,显然,在通用参数中,只允许来自文件的程序集。为了解决这个问题,我从 AppDomain
注册了 AssemblyResolve
事件,并处理了在文件中找不到 DynamicAssembly
的情况。我的工作代码:
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();
}
我正在使用 TypeBuilder
创建类型。然后将这些类型用作泛型 class 中的参数。我想要做的是从它的名字创建 Type
。通用参数是动态的这一事实似乎是一个障碍。
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();
}
}
显然我知道如何从 MakeGenericType
创建 Type
,但在我正在处理的现实场景中,我不想(或不能)破坏键入名称,以便我可以单独创建类型并将它们拼凑在一起。
如何从 string
名称重新创建这种 Type
?
我突然想到我应该使用 Assembly.GetType()
的版本,它会在错误时抛出 Exception
。它抛出一个 FileNotFoundException
,显然,在通用参数中,只允许来自文件的程序集。为了解决这个问题,我从 AppDomain
注册了 AssemblyResolve
事件,并处理了在文件中找不到 DynamicAssembly
的情况。我的工作代码:
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();
}