从具有基类和其他字段的TypeBuilder创建动态类型会生成异常

本文关键字:类型 动态 创建 异常 TypeBuilder 基类 字段 其他 | 更新日期: 2023-09-27 18:29:14

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

我创建指定基类型的TypeBuilder,然后向其添加公共字段,最后调用CreateType()。由此产生的错误消息是:

未能从程序集"MyDynamicAssembly"加载类型"InternalType",Version=0.0.0.0,Culture=neutral,PublicKeyToken=null,因为字段没有为"first"指定显式偏移量。"

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

这是代码:

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;
    }

从具有基类和其他字段的TypeBuilder创建动态类型会生成异常

好吧,我在发布后不久就明白了。我确实看错了错误信息。事实上,它与继承的基类无关。

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

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;
    }

编辑:以上代码不起作用。字段索引是以字节为单位的,所以当你增加偏移量时,你应该按照字段的大小这样做:

fieldOffset += sizeof(Int32);