2013-08-27 2 views
6

Я пытаюсь создать динамический тип на основе существующего типа, который содержит только общедоступные поля. Новый динамический тип также должен наследоваться от другого базового типа, который имеет только полностью реализованный метод.Создание динамического типа из TypeBuilder с базовым классом и дополнительными полями генерирует исключение

Я создаю TypeBuilder, указав базовый тип, затем добавлю к нему открытые поля, и, наконец, я вызываю CreateType(). Сообщение в результате ошибки:

«Не удалось загрузить тип 'InternalType' из сборки 'MyDynamicAssembly, Version = 0.0.0.0, культура = нейтральной, PublicKeyToken = NULL', потому что поле 'первый' не было дано явное смещение ".

Для меня это означает, что метод CreateType ищет общедоступное поле «первым» в базовом классе, что является проблемой, потому что его нет. Почему он считает, что добавленное поле должно быть в базовом классе? Или я не понимаю исключения?

Вот код:

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

ответ

8

Хорошо, я понял это моменты после размещения. Я действительно неправильно прочитал сообщение об ошибке. Фактически, это не имело никакого отношения к унаследованному базовому классу.

Когда я создал тип, я указал атрибут «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; 
    } 

EDIT: Приведенный выше код не работает. Индекс поля находится в байтах, поэтому, когда вы увеличиваете смещение, вы должны делать это по размеру поля следующим образом:

fieldOffset += sizeof(Int32); 
+1

Почему требуется «ExplicitLayout»? – svick

+0

svick, требуется сторонняя библиотека, которая использует неуправляемый код для взаимодействия с программируемым логическим контроллером (PLC). Я не спрашивал конкретно, может быть, SequentialLayout хватит. – dtaylor

+0

'CreateType' выдает мне ошибку:« System.TypeLoadException »в файле mscorlib.dll. Он говорит, что мой тип имеет недопустимый формат, почему? – vulkanino

 Смежные вопросы

  • Нет связанных вопросов^_^