.NET TypeBuilder - VerificationException:操作可能会破坏运行时的稳定性

发布于 2024-09-16 06:17:00 字数 4372 浏览 7 评论 0原文

我需要使用 TypeBuilder 在运行时创建一个类型。该类型应该实现特定的接口,以便可以在编译时统一处理该动态类型的实例。

该接口应返回一个对象数组,其中填充了该类型的特定字段的值。

应该实现的接口定义如下:

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 方法时,都会出现 VerificationException 并显示消息“操作可能会破坏运行时的稳定性”。被抛出。我不知道是什么原因造成的。有人可以帮忙吗?

谢谢你!

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.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();
}

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

时常饿 2024-09-23 06:17:00

stelem.ref 操作码将对象引用存储到数组中。这意味着如果您有值类型的字段(例如int),那么您需要确保在将它们存储到数组之前将它们装箱。 添加类似内容

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

因此,您应该在 stelem.ref 指令之前

。另外,虽然这不会导致验证异常,但请注意,您的属性的方法名称应该是 get_{Name}set_{Name},而不是 {Name }_get{Name}_set

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.

ぽ尐不点ル 2024-09-23 06:17:00

您没有声明局部变量,但使用了它(Stloc_0Ldloc_0)。

在生成 IL 代码之前插入以下内容:

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

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[]));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文