【问题标题】:Creating dynamic type from TypeBuilder with a base class and additional fields generates an exception使用基类和附加字段从 TypeBuilder 创建动态类型会生成异常
【发布时间】:2013-08-30 07:21:46
【问题描述】:

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

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

“无法从程序集“MyDynamicAssembly”加载类型“InternalType”, 版本=0.0.0.0,文化=中性,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;
    }

【问题讨论】:

  • 能否请您展示一下如何使用 ToDynamic(..) 方法?
  • 感谢您提供这个非常好的主题。但是你不是用基类复制一个新类,而不是从基类继承吗?

标签: c# inheritance reflection reflection.emit typebuilder


【解决方案1】:

好的,我在发布后不久就想通了。我确实误读了错误消息。实际上,它与继承的基类无关。

当我创建类型时,我指定了必需的属性“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);

【讨论】:

  • 为什么需要ExplicitLayout
  • svick,它是使用非托管代码与可编程逻辑控制器 (PLC) 接口的第 3 方库所必需的。我没有具体问,可能SequentialLayout就够用了。
  • CreateType 为我抛出错误:mscorlib.dll 中的“System.TypeLoadException”。它说我的类型格式无效,为什么?
  • vulkanino,只是一个建议,但您应该尝试开始新的尝试。大多数人不会阅读已标记为“已回答”的主题。祝你好运。
  • @dtaylor,也许你应该使用TypeBuilder.SetParent(Type) 告诉新继承的类它被继承了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-29
相关资源
最近更新 更多