dta*_*lor 8 c# reflection inheritance reflection.emit typebuilder
我正在尝试基于仅包含公共字段的现有类型创建动态类型.新的动态类型还必须从仅具有完全实现的方法的不同基类型继承.
我创建了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;
}
Run Code Online (Sandbox Code Playgroud)
好的,我在发布后想出了这个.我确实误读了错误信息.事实上,它与继承的基类无关.
当我创建类型时,我指定了所需的属性"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;
}
Run Code Online (Sandbox Code Playgroud)
编辑:上面的代码将无法正常工作.字段索引以字节为单位,因此当您增加偏移时,您应该按字段大小这样做:
fieldOffset += sizeof(Int32);
Run Code Online (Sandbox Code Playgroud)