从TypeBuilder创建具有基类和附加字段的动态类型会生成exception

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

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

“无法从程序集’MyDynamicAssembly,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null’加载类型’InternalType’,因为字段’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; } 

好的,我在发布后想出了这个。 我确实误读了错误信息。 事实上,它与inheritance的基类无关。

当我创建类型时,我指定了必需的属性“TypeAttributes.ExplicitLayout”。 不幸的是,我没有意识到在创建它们时我还必须为每个字段添加一个偏移量。 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) { 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);