2016-12-09 4 views
2

자체 참조 된 컬렉션 속성을 정의하는 방법? 유형 반사 유형 빌더로 빌드하고 싶습니다. 방법 : 리플렉션을 사용하여 자체 참조 유형 속성 정의 C#

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

코드

나는 당신이 필드를 방출하여 수동으로 "백업 필드"를 정의하고 속성에 대한 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); 
myType.DefineProperty("Items", PropertyAttributes.None, selfContained, null);     
Type type= myType.CreateType(); 
Activator.CreateInstance(type); 
myAssembly.Save(myAsmName.Name + ".dll"); 
+0

독자에게 명백한 오류가 있습니까? 문제가 무엇인지 설명하십시오. 바람직하지 않거나 예기치 않은 오류 메시지, 예외 세부 사항, 출력 또는 기타 동작을 포함시킵니다. –

+0

놀랍고 훌륭한. –

답변

1

물품.

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

감사합니다. Tony. 이 항목을 기본 생성자 내에서 초기화 할 수 있습니까? –

+0

예, 기본 생성자를 정의하고 필드를 설정할 수 있습니다. –

+0

안녕하세요, Tony, 초기화하려면 기본 생성자를 만들려고했지만 작동하지 않습니다. 위의 코드에 추가 할 수 있습니까? –