2013-11-24 99 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类型,它应该加载正常。由于载入子项时出现问题,父项未加载。