我需要在运行时使用TypeBuilder创建一个类型。这种类型应该实现一个特定的接口,以便可以在编译时统一处理这种动态类型的实例。.NET TypeBuilder - VerificationException:操作可能会破坏运行时的稳定性
接口应该返回一个填充了该类型中特定字段值的对象数组。是应该被实现被定义为
接口如下:
public interface ISelectable
{
object[] GetPrimaryKeysValues();
}
这是我使用以产生用于所述接口的方法的代码:所述方法被认为
public static Type BuildTypeFromTable(Table tableToBuildTypeFrom)
{
AssemblyBuilder customTypesAssembly =
AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("CustomTypesAssembly"), AssemblyBuilderAccess.Run);
ModuleBuilder _moduleBuilder = customTypesAssembly.DefineDynamicModule("CustomTypesModule");
TypeBuilder customTypeBuilder = _moduleBuilder.DefineType(Guid.NewGuid().ToString(), TypeAttributes.Public | TypeAttributes.Class);
List<FieldBuilder> primaryKeyFields = new List<FieldBuilder>();
//create a property for each column in the table
for (int i = 0; i < tableToBuildTypeFrom.Columns.Count; i++)
{
string propertyName = tableToBuildTypeFrom.Columns[i].Name;
//get a type of a property to create from a first row of the table
Type propertyType = tableToBuildTypeFrom.GetTypeOfColumnAtIndex(i);
//each property has to have a field to store its value in
FieldBuilder backingField = customTypeBuilder.DefineField(propertyName + "_field", propertyType, FieldAttributes.Private);
//body of a property getter
MethodBuilder getMethod = customTypeBuilder.DefineMethod(propertyName + "_get", MethodAttributes.Public | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIlGenerator = getMethod.GetILGenerator();
getIlGenerator.Emit(OpCodes.Ldarg_0);
getIlGenerator.Emit(OpCodes.Ldfld, backingField);
getIlGenerator.Emit(OpCodes.Ret);
///body of a property setter
MethodBuilder setMethod = customTypeBuilder.DefineMethod(propertyName + "_set", MethodAttributes.Public | MethodAttributes.HideBySig, null, new Type[] { propertyType });
ILGenerator setIlGenerator = setMethod.GetILGenerator();
setIlGenerator.Emit(OpCodes.Ldarg_0);
setIlGenerator.Emit(OpCodes.Ldarg_1);
setIlGenerator.Emit(OpCodes.Stfld, backingField);
setIlGenerator.Emit(OpCodes.Ret);
PropertyBuilder customProperty = customTypeBuilder.DefineProperty(propertyName, PropertyAttributes.None, propertyType, Type.EmptyTypes);
customProperty.SetGetMethod(getMethod);
customProperty.SetSetMethod(setMethod);
//save all primary key columns to avoid iterating over columns all over again
if (tableToBuildTypeFrom.Columns[i].IsPrimaryKey)
{
primaryKeyFields.Add(backingField);
}
}
customTypeBuilder.AddInterfaceImplementation(typeof(ISelectable));
MethodBuilder getPrimaryKeysMethod = customTypeBuilder.DefineMethod("GetPrimaryKeysValues", MethodAttributes.Public | MethodAttributes.Virtual, typeof(object[]), null);
ILGenerator getPrimaryKeysMethodIlGenerator = getPrimaryKeysMethod.GetILGenerator();
getPrimaryKeysMethodIlGenerator.DeclareLocal(typeof(object[]));
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldc_I4, primaryKeyFields.Count);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Newarr, typeof(object));
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Stloc_0);
for (int i = 0; i < primaryKeyFields.Count; i++)
{
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldloc_0);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldc_I4, i);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldarg_0);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldfld, primaryKeyFields[i]);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Stelem_Ref);
}
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ldloc_0);
getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Ret);
MethodInfo s = typeof(ISelectable).GetMethod("GetPrimaryKeysValues");
customTypeBuilder.DefineMethodOverride(getPrimaryKeysMethod, s);
return customTypeBuilder.CreateType();
}
的方式从MSDN取得。
现在,问题是每次我尝试调用GetPrimaryKeysValues方法时,带有消息'Operation的VerificationException可能会破坏运行时的稳定性。'被抛出。我不知道是什么导致它。有人可以帮忙吗?
谢谢!
谢谢你,这个伎俩! 我只需要改变你的代码 - 为了使它工作,Box操作码的Type参数应该是typeof(primaryKeyFields [i] .FieldType),而不是typeof(object)。否则,我得到了FatalExecutionEngineError。 我也改变了我的属性方法名称,正如你所建议的。这是一种命名约定吗? – 2010-08-25 21:16:47
@Lotar - 是的,这是公共语言规范使用的命名约定(请参阅http://msdn.microsoft.com/en-us/library/12a7a7h3.aspx中的“访问者名称”部分)。我编辑了我的答案,以修复盒子指令使用的类型。 – kvb 2010-08-26 05:24:16