从TypeBuilder创建具有基类和附加字段的动态类型会生成异常 [英] Creating dynamic type from TypeBuilder with a base class and additional fields generates an exception

查看:211
本文介绍了从TypeBuilder创建具有基类和附加字段的动态类型会生成异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试基于仅包含公共字段的现有类型创建动态类型。新的动态类型还必须从仅具有完全实现的方法的不同基类型继承。

I am trying to create a dynamic type based on an existing type that contains only public fields. The new dynamic type must also inherit from a different base type which only has a fully implemented method.

我创建 TypeBuilder 指定基本类型然后我将公共字段添加到它,最后我调用 CreateType()。生成的错误消息为:

I create the TypeBuilder specifying the base type then I add the public fields to it and finally I call CreateType(). The resulting error message is:


无法从程序集'MyDynamicAssembly加载类型'InternalType',
版本= 0.0.0.0 ,Culture = neutral,PublicKeyToken = null'因为字段
'first'没有给出明确的偏移量。

"Could not load type 'InternalType' from assembly 'MyDynamicAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' because field 'first' was not given an explicit offset."

To我这意味着 CreateType 方法在基类中寻找公共字段first,这是一个问题,因为它不在那里。为什么它认为添加的字段应该在基类中?或者,我是否误解了这个例外?

To me this implies that the CreateType method is looking for the public field "first" in the base class which is a problem because it is not there. Why does it think the added field should be in the base class? Or, am I misunderstanding the exception?

以下是代码:

public class sourceClass
{
    public Int32 first = 1;
    public Int32 second = 2;
    public Int32 third = 3;
}

public static class MyConvert
{
    public static object ToDynamic(object sourceObject, out Type outType)
    {
        // get the public fields from the source object
        FieldInfo[] sourceFields = sourceObject.GetType().GetFields();

        // get a dynamic TypeBuilder and inherit from the base type
        AssemblyName assemblyName
            = new AssemblyName("MyDynamicAssembly");
        AssemblyBuilder assemblyBuilder
            = AppDomain.CurrentDomain.DefineDynamicAssembly(
                assemblyName,
                AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder
            = assemblyBuilder.DefineDynamicModule("MyDynamicModule");
        TypeBuilder typeBuilder
            = moduleBuilder.DefineType(
                "InternalType",
                TypeAttributes.Public
                | TypeAttributes.Class
                | TypeAttributes.AutoClass
                | TypeAttributes.AnsiClass
                | TypeAttributes.ExplicitLayout,
                typeof(SomeOtherNamespace.MyBase));

        // add public fields to match the source object
        foreach (FieldInfo sourceField in sourceFields)
        {
            FieldBuilder fieldBuilder
                = typeBuilder.DefineField(
                    sourceField.Name,
                    sourceField.FieldType,
                    FieldAttributes.Public);
        }

        // THIS IS WHERE THE EXCEPTION OCCURS
        // create the dynamic class
        Type dynamicType = typeBuilder.CreateType();

        // create an instance of the class
        object destObject = Activator.CreateInstance(dynamicType);

        // copy the values of the public fields of the
        // source object to the dynamic object
        foreach (FieldInfo sourceField in sourceFields)
        {
            FieldInfo destField
                = destObject.GetType().GetField(sourceField.Name);
            destField.SetValue(
                destObject,
                sourceField.GetValue(sourceField));
        }

        // give the new class to the caller for casting purposes
        outType = dynamicType;

        // return the new object
        return destObject;
    }


推荐答案

好的,我想出来了发布后的片刻。我确实误读了错误信息。事实上,它与继承的基类无关。

Ok, I figured this out moments after posting. I was indeed misreading the error message. It, in fact, had nothing to do with the inherited base class.

当我创建类型时,我指定了属性TypeAttributes.ExplicitLayout,这是必需的。不幸的是,我没有意识到在创建它们时我还必须为每个字段添加一个偏移量。异常消息完全准确。对不起,误报了。更正后的代码如下:

When I created the type I specified the attribute "TypeAttributes.ExplicitLayout" which is required. Unfortunately, I didn't realize that I had to also add an offset to each field when I created them. The exception message was completely accurate. Sorry for the false alarm. The corrected code follows:

public class SourceClass
{
    public Int32 first = 1;
    public Int32 second = 2;
    public Int32 third = 3;
}

public static class MyConvert
{
    public static object ToDynamic(object sourceObject, out Type outType)
    {
        Int32 fieldOffset = 0;

        // get the public fields from the source object
        FieldInfo[] sourceFields = sourceObject.GetType().GetFields();

        // get a dynamic TypeBuilder and inherit from the base type
        AssemblyName assemblyName
            = new AssemblyName("MyDynamicAssembly");
        AssemblyBuilder assemblyBuilder
            = AppDomain.CurrentDomain.DefineDynamicAssembly(
                assemblyName,
                AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder
            = assemblyBuilder.DefineDynamicModule("MyDynamicModule");
        TypeBuilder typeBuilder
            = moduleBuilder.DefineType(
                "InternalType",
                TypeAttributes.Public
                | TypeAttributes.Class
                | TypeAttributes.AutoClass
                | TypeAttributes.AnsiClass
                | TypeAttributes.ExplicitLayout,
                typeof(SomeOtherNamespace.MyBase));

        // add public fields to match the source object
        foreach (FieldInfo sourceField in sourceFields)
        {
            FieldBuilder fieldBuilder
                = typeBuilder.DefineField(
                    sourceField.Name,
                    sourceField.FieldType,
                    FieldAttributes.Public);
            fieldBuilder.SetOffset(fieldOffset);
            fieldOffset++;
        }

        // create the dynamic class
        Type dynamicType = typeBuilder.CreateType();

        // create an instance of the class
        object destObject = Activator.CreateInstance(dynamicType);

        // copy the values of the public fields of the
        // source object to the dynamic object
        foreach (FieldInfo sourceField in sourceFields)
        {
            FieldInfo destField
                = destObject.GetType().GetField(sourceField.Name);
            destField.SetValue(
                destObject,
                sourceField.GetValue(sourceObject));
        }

        // give the new class to the caller for casting purposes
        outType = dynamicType;

        // return the new object
        return destObject;
    }

编辑:上述代码不起作用。字段索引以字节为单位,因此当您增加偏移时,您应该按照字段的大小进行增加,如下所示:

The above code won't work. The field index is in bytes so when you increment the offset you should do so by the size of the field like so:

fieldOffset += sizeof(Int32);

这篇关于从TypeBuilder创建具有基类和附加字段的动态类型会生成异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆