使用 TypeBuilder 获取在运行时创建的 class 的类型
Getting the type of a class created during runtime using TypeBuilder
我有以下代码块,我正在使用 TypeBuilder 构建 class (SampleModel)。创建类型后,我将尝试使用 Type.GetType
获取我刚刚创建的 class 的 Type
。但是 Type.GetType
正在返回 null
。这是为什么?
namespace TypeBuilderTest
{
using System;
using System.Reflection;
using System.Reflection.Emit;
class Program
{
static void Main()
{
// create a dynamic assembly and module
var assemblyName = new AssemblyName("SampleModelAssembly");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
var runtimeModelType = CreateRuntimeModel(moduleBuilder);
var type = Type.GetType(runtimeModelType.AssemblyQualifiedName); // <= This is the call in question.
Console.WriteLine("Type: " + type);
}
static private Type CreateRuntimeModel(ModuleBuilder moduleBuilder)
{
var modelName = "SampleModel";
// create a new type builder
var typeBuilder = moduleBuilder.DefineType(
modelName,
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable);
AddProperty(typeBuilder, "SampleAttribute", typeof(string));
return typeBuilder.CreateType();
}
static public void AddProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
{
// Generate a private field
FieldBuilder field = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
// Generate a public property
//
// The last argument of DefineProperty is null, because the
// property has no parameters. (If you don't specify null, you must
// specify an array of Type objects. For a parameterless property,
// use the built-in array with no elements: Type.EmptyTypes)
PropertyBuilder property =
typeBuilder.DefineProperty(propertyName,
System.Reflection.PropertyAttributes.None,
propertyType,
null);
// The property set and property get methods require a special set of attributes:
MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
// Define the "get" accessor method for current private field.
MethodBuilder currGetPropMthdBldr =
typeBuilder.DefineMethod("get_value",
GetSetAttr,
propertyType,
Type.EmptyTypes);
ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
// For an instance property, argument zero is the instance. Load the
// instance, then load the private field and return, leaving the
// field value on the stack.
currGetIL.Emit(OpCodes.Ldarg_0);
currGetIL.Emit(OpCodes.Ldfld, field);
currGetIL.Emit(OpCodes.Ret);
// Define the "set" accessor method for current private field.
MethodBuilder currSetPropMthdBldr =
typeBuilder.DefineMethod("set_value",
GetSetAttr,
null,
new Type[] { propertyType });
ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
// Load the instance and then the numeric argument, then store the
// argument in the field.
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldarg_1);
currSetIL.Emit(OpCodes.Stfld, field);
currSetIL.Emit(OpCodes.Ret);
// Last, map the "get" and "set" accessor methods to the
// PropertyBuilder. The property is now complete.
property.SetGetMethod(currGetPropMthdBldr);
property.SetSetMethod(currSetPropMthdBldr);
}
}
}
runtimeModelType.AssemblyQualifiedName
显示 SampleModel, SampleModelAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
P.S:当我通过 LinqPad 运行 执行相同的程序时,间歇性地返回类型。其余时间,我也在那里得到 null 。
通过调用
获取类型类型
assemblyBuilder.GetType (runtimeModelType.FullName)
调用 Type.GetType 依靠融合来定位正确的程序集,我怀疑它可能不可靠,因为它是动态创建的。至少,它增加了一层不必要的复杂性。
LINQPad 有一个额外的钩子来帮助运行时查找程序集,这可能会使其(有时)起作用。
我有以下代码块,我正在使用 TypeBuilder 构建 class (SampleModel)。创建类型后,我将尝试使用 Type.GetType
获取我刚刚创建的 class 的 Type
。但是 Type.GetType
正在返回 null
。这是为什么?
namespace TypeBuilderTest
{
using System;
using System.Reflection;
using System.Reflection.Emit;
class Program
{
static void Main()
{
// create a dynamic assembly and module
var assemblyName = new AssemblyName("SampleModelAssembly");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
var runtimeModelType = CreateRuntimeModel(moduleBuilder);
var type = Type.GetType(runtimeModelType.AssemblyQualifiedName); // <= This is the call in question.
Console.WriteLine("Type: " + type);
}
static private Type CreateRuntimeModel(ModuleBuilder moduleBuilder)
{
var modelName = "SampleModel";
// create a new type builder
var typeBuilder = moduleBuilder.DefineType(
modelName,
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable);
AddProperty(typeBuilder, "SampleAttribute", typeof(string));
return typeBuilder.CreateType();
}
static public void AddProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
{
// Generate a private field
FieldBuilder field = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
// Generate a public property
//
// The last argument of DefineProperty is null, because the
// property has no parameters. (If you don't specify null, you must
// specify an array of Type objects. For a parameterless property,
// use the built-in array with no elements: Type.EmptyTypes)
PropertyBuilder property =
typeBuilder.DefineProperty(propertyName,
System.Reflection.PropertyAttributes.None,
propertyType,
null);
// The property set and property get methods require a special set of attributes:
MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
// Define the "get" accessor method for current private field.
MethodBuilder currGetPropMthdBldr =
typeBuilder.DefineMethod("get_value",
GetSetAttr,
propertyType,
Type.EmptyTypes);
ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
// For an instance property, argument zero is the instance. Load the
// instance, then load the private field and return, leaving the
// field value on the stack.
currGetIL.Emit(OpCodes.Ldarg_0);
currGetIL.Emit(OpCodes.Ldfld, field);
currGetIL.Emit(OpCodes.Ret);
// Define the "set" accessor method for current private field.
MethodBuilder currSetPropMthdBldr =
typeBuilder.DefineMethod("set_value",
GetSetAttr,
null,
new Type[] { propertyType });
ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
// Load the instance and then the numeric argument, then store the
// argument in the field.
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldarg_1);
currSetIL.Emit(OpCodes.Stfld, field);
currSetIL.Emit(OpCodes.Ret);
// Last, map the "get" and "set" accessor methods to the
// PropertyBuilder. The property is now complete.
property.SetGetMethod(currGetPropMthdBldr);
property.SetSetMethod(currSetPropMthdBldr);
}
}
}
runtimeModelType.AssemblyQualifiedName
显示 SampleModel, SampleModelAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
P.S:当我通过 LinqPad 运行 执行相同的程序时,间歇性地返回类型。其余时间,我也在那里得到 null 。
通过调用
获取类型类型assemblyBuilder.GetType (runtimeModelType.FullName)
调用 Type.GetType 依靠融合来定位正确的程序集,我怀疑它可能不可靠,因为它是动态创建的。至少,它增加了一层不必要的复杂性。
LINQPad 有一个额外的钩子来帮助运行时查找程序集,这可能会使其(有时)起作用。