Reflect radiation for the Getter property

I want to dynamically build the type as follows:

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

The code I'm writing is:

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

I think I am having a problem building the constructor and getter method for the Depth property.

Please help me out of this.

An instance is not created either.

thanks

+5
source share
1 answer

There are several problems in the code.

In the parent setter method, you missed the parameter declaration:

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

Here you declare a redundant support field, just delete this line:

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

Your deepth property is of the wrong type, it must be of type int:

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

The IL code that you generate for your computed property looks like debugging code, I replaced it with the release code. You also emit incomplete branch instructions, you must pass the target label as the second parameter, look at this working method:

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

Last but not least, you must wrap your null argument in an array of objects so that the activator can find the expected constructor overload:

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

Source: https://habr.com/ru/post/1262067/


All Articles