开发者

.NET TypeBuilder - VerificationException: Operation could destabilize the runtime

开发者 https://www.devze.com 2023-01-13 15:30 出处:网络
I need to create a type at runtime using the TypeBuilder. This type should implement a specific interface so that it is possible to treat instances of this dynamic type uniformly at the compile time.

I need to create a type at runtime using the TypeBuilder. This type should implement a specific interface so that it is possible to treat instances of this dynamic type uniformly at the compile time.

The interface should return an array of objects filled with values of specific fields in that type.

Interface that is supposed to be implemented is defined as follows:

public interface ISelectable
{
    object[] GetPrimaryKeysValues();
}

This is the code I use to generate a method for the interface:

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.Ldf开发者_运维知识库ld, 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();
}

The way the method is supposed to be generated is taken from MSDN.

Now, the problem is that each time I try to call GetPrimaryKeysValues method, the VerificationException with a message 'Operation could destabilize the runtime.' is thrown. I have no idea what is causing it. Could someone help?

Thank you!


The stelem.ref opcode stores an object reference into an array. This means that if you have fields of value types (e.g. ints), then you need to make sure to box them before storing them into the array. Therefore, you should add something like

if (primaryKeyFields[i].FieldType.IsValueType) {
    getPrimaryKeysMethodIlGenerator.Emit(OpCodes.Box, primaryKeyFields[i].FieldType);
}

immediately before the stelem.ref instruction.

Also, although this should not cause the verification exception, note that your properties' method names should be get_{Name} and set_{Name}, not {Name}_get and {Name}_set.


You didn't declare local variable, but you use it (Stloc_0,Ldloc_0).

Insert this right before generating IL code:

getPrimaryKeysMethodIlGenerator.DeclareLocal(typeof(object[]));
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号