如何:在C#中使用反射发射定义自引用类型属性 [英] How to: Define a Self Referenced Type Property with Reflection Emit in c#
本文介绍了如何:在C#中使用反射发射定义自引用类型属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
如何定义自引用集合属性?
我要使用反射类型生成器构建的类型。
How to define self referenced collection property ? Type I want to build with Reflection Type Builder.
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");
推荐答案
您必须通过以下方式手动定义后备字段
You have to define manually the "backing field" by emitting field and define getter and setter for your property.
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);
这篇关于如何:在C#中使用反射发射定义自引用类型属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文