2013-11-24 4 views
3

Я пытаюсь использовать Refle.emit генерировать следующий класс:Использование отражения для определения свойства с TYPEOF вложенного типа

public class Parent { 
    public class Child { } 
    public Child MyChild { get; set; } 
} 

Так вот что сделал:

static void Main(string[] args) { 
    AssemblyName newAssembly = new AssemblyName("myAssembly"); 
    AppDomain appDomain = System.Threading.Thread.GetDomain(); 
    AssemblyBuilder assemblyBuilder = 
    appDomain.DefineDynamicAssembly(newAssembly, AssemblyBuilderAccess.RunAndSave); 
    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(newAssembly.Name); 

    TypeBuilder parentBuilder = moduleBuilder.DefineType("Parent"); 
    TypeBuilder childBuilder = parentBuilder.DefineNestedType("Child"); 
    parentBuilder.DefineProperty("MyProperty", PropertyAttributes.None, childBuilder.CreateType(), null); 
    parentBuilder.CreateType(); 
} 

я получаю исключение : «Не удалось загрузить тип« Родитель »из сборки« myAssembly »в parentBuilder.DefineProperty (...,

Я не нашел способа создать родительский класс без создания дочернего класса в другая сборка. Какие-либо предложения?

ответ

2

Вы можете создать родительский класс, не создавая дочерний класс в другой сборке, и на самом деле ваш код близок к правилу. В вас код у вас есть одна ошибка в строке:

parentBuilder.DefineProperty("MyProperty", PropertyAttributes.None, childBuilder.CreateType(), null); 

Здесь вы пытаетесь CreateType вложенного типа, который является ненужным в данный момент. Вы можете предоставить только TypeBuilder для него:

parentBuilder.DefineProperty("MyProperty", PropertyAttributes.None, childBuilder, null); 

Но помните, что определение свойства таким образом, не хватает. Вы должны предоставить реализацию для своего сеттера и getter (и, возможно, поля поддержки). Здесь у вас есть рабочий пример для генерации класса:

public class Parent 
{ 
    public class Child 
    { 
    } 
    private Parent.Child myChild; 
    public Parent.Child MyChild 
    { 
     get 
     { 
      return this.myChild; 
     } 
     set 
     { 
      this.myChild = value; 
     } 
    } 
} 

Код:

TypeBuilder parentBuilder = moduleBuilder.DefineType("Parent", TypeAttributes.Public); 
TypeBuilder childBuilder = parentBuilder.DefineNestedType("Child", TypeAttributes.NestedPublic); 
PropertyBuilder propertyBuilder = parentBuilder.DefineProperty("MyChild", PropertyAttributes.None, childBuilder, null); 

// Define field 
FieldBuilder fieldBuilder = parentBuilder.DefineField("myChild", childBuilder, FieldAttributes.Private); 
// Define "getter" for MyChild property 
MethodBuilder getterBuilder = parentBuilder.DefineMethod("get_MyChild", 
            MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, 
            childBuilder, 
            Type.EmptyTypes); 
ILGenerator getterIL = getterBuilder.GetILGenerator(); 
getterIL.Emit(OpCodes.Ldarg_0); 
getterIL.Emit(OpCodes.Ldfld, fieldBuilder); 
getterIL.Emit(OpCodes.Ret); 

// Define "setter" for MyChild property 
MethodBuilder setterBuilder = parentBuilder.DefineMethod("set_MyChild", 
            MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, 
            null, 
            new Type[] { childBuilder }); 
ILGenerator setterIL = setterBuilder.GetILGenerator(); 
setterIL.Emit(OpCodes.Ldarg_0); 
setterIL.Emit(OpCodes.Ldarg_1); 
setterIL.Emit(OpCodes.Stfld, fieldBuilder); 
setterIL.Emit(OpCodes.Ret); 

propertyBuilder.SetGetMethod(getterBuilder); 
propertyBuilder.SetSetMethod(setterBuilder); 
+0

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

+0

Добро пожаловать в SO! Поскольку вы новичок, вы можете проверить эту ссылку. –

0

В моем примере ниже, я извлекал создание типа ребенка, чтобы сосредоточиться на отладку создания родительского типа:.

public static Type BuildType() { 
     AssemblyName newAssembly = new AssemblyName("myAssembly"); 
     //AppDomain appDomain = System.Threading.Thread.GetDomain(); 

     AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain 
      .DefineDynamicAssembly(
      newAssembly, 
      AssemblyBuilderAccess.RunAndSave); 

     ModuleBuilder moduleBuilder = assemblyBuilder 
      .DefineDynamicModule(newAssembly.Name, newAssembly.Name + ".dll"); 

     TypeBuilder parentBuilder = moduleBuilder.DefineType(
      "Parent", TypeAttributes.Public); 

     var ctor0 = parentBuilder.DefineConstructor(
      MethodAttributes.Public, 
      CallingConventions.Standard, 
      Type.EmptyTypes); 

     ILGenerator ctor0IL = ctor0.GetILGenerator(); 
     // For a constructor, argument zero is a reference to the new 
     // instance. Push it on the stack before pushing the default 
     // value on the stack, then call constructor ctor1. 
     ctor0IL.Emit(OpCodes.Ldarg_0); 
     ctor0IL.Emit(OpCodes.Ldc_I4_S, 42); 
     ctor0IL.Emit(OpCodes.Call, ctor0); 
     ctor0IL.Emit(OpCodes.Ret); 

     //TypeBuilder childBuilder = parentBuilder.DefineNestedType("Child"); 
     //var chType = childBuilder.CreateType(); 

     parentBuilder.DefineProperty(
      "MyProperty", 
      PropertyAttributes.HasDefault, 
      typeof(string), 
      //childBuilder.CreateType(), 
      null); 
     var type = parentBuilder.CreateType(); 

     assemblyBuilder.Save(newAssembly.Name + ".dll"); 


     return type; 
    } 

Я добавил пару вещей, как я шел вдоль (включая default ctor). Я получил это от MSDN Assembly Builder.

В любом случае, это компилируется и запускается. Проблема (я сильно подозреваю) заключается в том, что вы не заполняете тип Child в своем коде. Заполните тип Child, и он должен загрузиться штрафом. Родитель не загружается из-за проблемы загрузки Child.

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