【问题标题】:How to: Define a Self Referenced Type Property with Reflection Emit in c#如何:在 c# 中使用反射发射定义自引用类型属性
【发布时间】:2017-04-24 15:23:17
【问题描述】:

如何定义自引用集合属性? 我想用反射类型构建器构建的类型。

public class Sample
{
    public Sample()
    {
       Items = new List<Sample>();
    }
    public List<Sample> Items { get; set; }
    Public void AddSample(Sample item)
    {
       items.Add(item);
    }
}

我写的代码

AppDomain myDomain = AppDomain.CurrentDomain;
AssemblyName myAsmName = new AssemblyName("GenericEmit");
AssemblyBuilder myAssembly = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave);

ModuleBuilder myModule = myAssembly.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll");
TypeBuilder myType = myModule.DefineType("Sample", TypeAttributes.Public);  
Type listOf = typeof(List<>);
Type selfContained = listOf.MakeGenericType(myType);
myType.DefineProperty("Items", PropertyAttributes.None, selfContained, null);                
Type type= myType.CreateType();
Activator.CreateInstance(type);
myAssembly.Save(myAsmName.Name + ".dll");

【问题讨论】:

  • 是否存在对读者来说应该很明显的错误?请说明问题是什么。包括错误消息、异常详细信息、输出或其他不希望或意外的行为。
  • 非常棒。

标签: c# reflection collections typebuilder


【解决方案1】:

您必须通过发出字段手动定义“支持字段”并为您的属性定义 getter 和 setter。

AppDomain myDomain = AppDomain.CurrentDomain;
AssemblyName myAsmName = new AssemblyName("GenericEmit");
AssemblyBuilder myAssembly = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.RunAndSave);

ModuleBuilder myModule = myAssembly.DefineDynamicModule(myAsmName.Name, myAsmName.Name + ".dll");
TypeBuilder myType = myModule.DefineType("Sample", TypeAttributes.Public);
Type listOf = typeof(List<>);
Type selfContained = listOf.MakeGenericType(myType);

//define a backingfield
FieldBuilder field = myType.DefineField("<Items>_BackingField", selfContained, FieldAttributes.Private);

//define a parameterless constructor to initialize the field.
ConstructorBuilder constructor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);
ILGenerator constructorBody = constructor.GetILGenerator();
constructorBody.Emit(OpCodes.Ldarg_0);
constructorBody.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
constructorBody.Emit(OpCodes.Ldarg_0);
constructorBody.Emit(OpCodes.Newobj, TypeBuilder.GetConstructor(selfContained, listOf.GetConstructor(Type.EmptyTypes)));
constructorBody.Emit(OpCodes.Stfld, field);
constructorBody.Emit(OpCodes.Ret);

//define the getter
MethodBuilder getter = myType.DefineMethod("get_Items", MethodAttributes.Public | MethodAttributes.HideBySig, selfContained, Type.EmptyTypes);
ILGenerator getterBody = getter.GetILGenerator();
getterBody.Emit(OpCodes.Ldarg_0);
getterBody.Emit(OpCodes.Ldfld, field);
getterBody.Emit(OpCodes.Ret);

//define the setter
MethodBuilder setter = myType.DefineMethod("set_Items", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(void), new Type[] { selfContained });
ILGenerator setterBody = setter.GetILGenerator();
setterBody.Emit(OpCodes.Ldarg_0);
setterBody.Emit(OpCodes.Ldarg_1);
setterBody.Emit(OpCodes.Stfld, field);
setterBody.Emit(OpCodes.Ret);

PropertyBuilder property = myType.DefineProperty("Items", PropertyAttributes.None, selfContained, null);

//Bind getter and setter
property.SetGetMethod(getter);
property.SetSetMethod(setter);

//AddSample method
var addSampleMethod = myType.DefineMethod("AddSample", MethodAttributes.Private, CallingConventions.HasThis, typeof(void), new Type[] { myType }};
var addSampleMethodBody = addSampleMethod.GetILGenerator();
addSampleMethodBody.Emit(OpCodes.Ldarg_0);
addSampleMethodBody.Emit(OpCodes.Ldfld, field);
addSampleMethodBody.Emit(OpCodes.Ldarg_1);
addSampleMethodBody.Emit(OpCodes.Callvirt, TypeBuilder.GetMethod(selfContained, typeof(List<>).GetMethod("Add"));
addSampleMethodBody.Emit(OpCodes.Ret);

Type type = myType.CreateType();
myAssembly.Save(myAsmName.Name + ".dll");

var sample = Activator.CreateInstance(type);

【讨论】:

  • 谢谢托尼。这个 Items 可以在默认构造函数中初始化吗?
  • 是的,你可以定义一个默认的构造函数并设置字段。
  • 嗨,托尼,我试图让默认构造函数初始化,但它不起作用。可以加到上面的代码吗?
  • 嗨,我编辑了我的帖子以添加无参数构造函数。
  • 感谢 Tony,我在 ConstuctorInfo 上遇到了一些错误,并更正如下:Type[] ctorArgs = { listOf }; ConstructorInfo ctorPrep = listOf.GetConstructor(ctorArgs); ConstructorInfo ci = TypeBuilder.GetConstructor(selfContained, ctorPrep);它生成类型但在 Activator.CreateInstance(type) 上出现错误
猜你喜欢
  • 2017-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-22
  • 2010-10-25
  • 2021-01-16
  • 1970-01-01
相关资源
最近更新 更多