使用反射来定义具有typeof嵌套类型的属性

时间:2013-11-24 13:17:40

标签: c# .net reflection.emit

我正在尝试使用Refle.emit来生成以下类:

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

我得到一个例外: “无法在parentBuilder.DefineProperty(...,

中从程序集'myAssembly'加载类型'Parent'

我没有找到任何方法来创建父类而不在另一个程序集中创建子类。有什么建议吗?

2 个答案:

答案 0 :(得分:3)

您可以创建父类而无需在其他程序集中创建子类,实际上您的代码接近正确。在你的代码中,你有一个错误:

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

答案 1 :(得分:0)

在下面的示例中,我删除了Child类型的创建,专注于调试父类型的创建:

    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时出现问题,因此未加载父。