2016-12-09 14 views
2

自己参照型コレクションプロパティを定義する方法は? タイプReflection Type Builderでビルドします。 方法:リフレクトを使用して自己参照型プロパティを定義する方法C#

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

トニーに感謝します。このアイテムはデフォルトのコンストラクタ内で初期化できますか? –

+0

はい、デフォルトコンストラクタを定義してフィールドを設定できます。 –

+0

こんにちはトニー、私は初期化するためにデフォルトのコンストラクタを作ろうとしましたが、動作しません。上のコードに追加できますか? –