2016-12-30 8 views
5

Я хочу построить тип динамически, как это:Отражение Выделяют для недвижимости Getter

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

Я думаю, что у меня была проблема в создании конструктора и глубины метода свойство геттер ,

Пожалуйста, помогите мне выбраться из этого.

Экземпляры не создаются.

Thanks

ответ

3

В коде есть несколько проблем.

В вашем методе родительского сеттера вы пропустили объявить параметр:

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

Вы объявляете избыточное поле подкладочного здесь, просто удалите эту строку:

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

Вашего deepth свойство из неправильный тип, он должен быть типа int:

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

Код IL, который вы ge 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); 

И последнее, но не в последнюю очередь, вы должны обернуть нулевой аргумент в массиве объектов так что активатор может найти ожидаемую перегрузку конструктора:

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

Благодарим вас, теневой, за ваши комментарии и исправления. Это очень мило с твоей стороны. –

 Смежные вопросы

  • Нет связанных вопросов^_^