반사

2016-12-30 8 views
5

내가 같이 동적으로 유형을 구축하려는 속성 게터에 대한 방출 :반사

public class Sample 
{ 
    Sample Parent { get; set; } 
    public Sample(Sample parent) 
    { 
     Parent = parent; 
    } 

    public int Depth 
    { 
     get 
     { 
      if (Parent == null) 
       return -1; 
      else 
       return Parent.Depth + 1; 
     } 
    } 
} 

내가 작성하는 코드 것은 :

 const string assemblyName = "SampleAssembly"; 
     const string parentPproperty = "Parent"; 
     const string depthProperty = "Depth"; 
     const string typeName = "Sample";  
     const string assemblyFileName = assemblyName + ".dll"; 

     AppDomain domain = AppDomain.CurrentDomain; 
     AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.RunAndSave); 
     ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName, assemblyFileName); 
     TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public); 
     FieldBuilder parentField = typeBuilder.DefineField($"_{parentPproperty}", typeBuilder, FieldAttributes.Private); 
     PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(parentPproperty, PropertyAttributes.None, parentField.FieldType, Type.EmptyTypes); 
     MethodAttributes getSetAttr = MethodAttributes.Public | 
     MethodAttributes.SpecialName | MethodAttributes.HideBySig; 

     MethodBuilder getParentMethod = typeBuilder.DefineMethod($"get_{propertyBuilder.Name}", getSetAttr, parentField.FieldType, Type.EmptyTypes); 
     ILGenerator il = getParentMethod.GetILGenerator(); 
     il.Emit(OpCodes.Ldarg_0); 
     il.Emit(OpCodes.Ldfld, parentField); 
     il.Emit(OpCodes.Ret); 
     propertyBuilder.SetGetMethod(getParentMethod); 

     MethodBuilder setParentMethod = typeBuilder.DefineMethod($"set_{propertyBuilder.Name}", qetSetAttr, null, Type.EmptyTypes); 
     il = setParentMethod.GetILGenerator(); 
     il.Emit(OpCodes.Ldarg_0); 
     il.Emit(OpCodes.Ldarg_1); 
     il.Emit(OpCodes.Stfld, parentField); 
     il.Emit(OpCodes.Ret); 
     propertyBuilder.SetSetMethod(setParentMethod); 


     parentField = typeBuilder.DefineField($"_{depthProperty}", typeBuilder, FieldAttributes.Private); 
     propertyBuilder = typeBuilder.DefineProperty(depthProperty, PropertyAttributes.None, parentField.FieldType, Type.EmptyTypes); 
     MethodBuilder getDepthMethod = typeBuilder.DefineMethod($"get_{depthProperty}", getSetAttr , parentField.FieldType, Type.EmptyTypes); 
     il = getDepthMethod.GetILGenerator(); 
     LocalBuilder lb = il.DeclareLocal(typeof(bool)); 

     il.Emit(OpCodes.Ldarg_0); 
     il.Emit(OpCodes.Call, getParentMethod); 
     il.Emit(OpCodes.Ldnull); 
     il.Emit(OpCodes.Ceq); 
     il.Emit(OpCodes.Stloc_0); 
     il.Emit(OpCodes.Ldloc_0); 
     il.Emit(OpCodes.Brfalse_S); 
     il.Emit(OpCodes.Ldc_I4_1); 
     il.Emit(OpCodes.Stloc_1); 
     il.Emit(OpCodes.Br_S); 
     il.Emit(OpCodes.Ldarg_0); 
     il.Emit(OpCodes.Call, getParentMethod); 
     il.Emit(OpCodes.Callvirt, getDepthMethod); 
     il.Emit(OpCodes.Ldc_I4_1); 
     il.Emit(OpCodes.Add); 
     il.Emit(OpCodes.Stloc_1); 
     il.Emit(OpCodes.Br_S); 
     il.Emit(OpCodes.Ldloc_1); 
     il.Emit(OpCodes.Ret); 
     propertyBuilder.SetGetMethod(getDepthMethod); 

     ConstructorBuilder constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { typeBuilder }); 
     il= constructor.GetILGenerator();    
     il.Emit(OpCodes.Ldarg_0); 
     il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); 
     il.Emit(OpCodes.Ldarg_0); 
     il.Emit(OpCodes.Ldarg_1); 
     il.Emit(OpCodes.Call, setParentMethod);   
     il.Emit(OpCodes.Ret); 

     Type type = typeBuilder.CreateType(); 
     var obj1 = Activator.CreateInstance(type, null); 

     var obj2 = Activator.CreateInstance(type, obj1); 

     assemblyBuilder.Save(assemblyFileName); 

은 내가 생성자와 깊이 속성 getter 메소드 구축에 문제가 있다고 생각 .

제발 나 좀 도와주세요.

인스턴스도 생성되지 않습니다.

감사합니다.

답변

3

코드에 몇 가지 문제점이 있습니다. 그냥이 줄을 삭제,

MethodBuilder setParentMethod = typeBuilder.DefineMethod($"set_{propertyBuilder.Name}", getSetAttr, null, new [] { propertyBuilder.PropertyType }); 

현재 중복 백업 필드를 선언됩니다 : 당신의 부모 setter 메소드에서

당신은 매개 변수를 선언 놓친 귀하의 deepth 속성이입니다

parentField = typeBuilder.DefineField($"_{depthProperty}", typeBuilder, FieldAttributes.Private); 

잘못된 유형 인 경우 int 유형이어야합니다.

propertyBuilder = typeBuilder.DefineProperty(depthProperty, PropertyAttributes.None, typeof(int), Type.EmptyTypes); 
MethodBuilder getDepthMethod = typeBuilder.DefineMethod($"get_{depthProperty}", getSetAttr, propertyBuilder.PropertyType, Type.EmptyTypes); 

IL 코드 귀하의 계산 속성에 대한 nerating 코드를 디버깅하는 것, 나는 그것을 릴리스 코드로 교체. 또한이 지침을 분기 불완전 방출되어, 당신은 두 번째 매개 변수로 대상 레이블을 통과이 작업 methodbody을 살펴이 있어야합니다

il = getDepthMethod.GetILGenerator(); 

var notNullLabel = il.DefineLabel(); 

il.Emit(OpCodes.Ldarg_0); 
il.Emit(OpCodes.Call, getParentMethod); 
il.Emit(OpCodes.Brtrue_S, notNullLabel); 
il.Emit(OpCodes.Ldc_I4_M1); 
il.Emit(OpCodes.Ret); 
il.MarkLabel(notNullLabel); 
il.Emit(OpCodes.Ldarg_0); 
il.Emit(OpCodes.Call, getParentMethod); 
il.Emit(OpCodes.Callvirt, getDepthMethod); 
il.Emit(OpCodes.Ldc_I4_1); 
il.Emit(OpCodes.Add); 
il.Emit(OpCodes.Ret); 

마지막으로, 당신은 너무 객체 배열에 null 인수를 마무리해야 액티베이터는 예상되는 생성자 오버로드를 찾을 수 있습니다.

var obj1 = Activator.CreateInstance(type, new object[] { null }); 
+0

감사와 수정을 위해 감사합니다. 그것은 당신의 아주 좋은 일입니다. –