2013-11-24 50 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中加載'Parent'類型...(

我沒有找到任何方法來創建父類而不創建子類一個不同的組件。有什麼建議麼?

回答

2

您可以創建父類,而無需在不同的程序集中創建子類,事實上您的代碼幾乎是正確的。在你的代碼,你有相符的一個錯誤:

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

在這裏,您試圖嵌套類型,它是在這一刻不必要的CreateType。你可以只是一個TypeBuilder爲它提供:

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

但請記住,這定義在這種方式財產不足以。你必須爲它的setter和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; 
    } 

我加了幾件事情,因爲我是打算一起(包括在默認ctor)。我從MSDN Assembly Builder得到了這個。

無論如何,這個編譯和運行。問題(我強烈懷疑)是你沒有在你的代碼中完成Child類型。完成Child類型,它應該加載正常。由於載入子項時出現問題,父項未加載。