0

Let us imaging we emit a class representing circle. We define a double property representing its radius, with correlating backing field and get/set accessors. Then we prepare a logic of computing area, in a form of anonymous method, using newly created PropertyBuilder.

var assemblyName = new AssemblyName();
assemblyName.Name = "SampleAssembly";
var domain = Thread.GetDomain();
var assembly = domain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
var module = assembly.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll", true);
var baseType = typeof(object);
var type = module.DefineType("Circle", TypeAttributes.Public, baseType);
var propertyType = typeof(double);
var radiusProperty = type.DefineProperty("Radius", PropertyAttributes.None, propertyType, null);
var backingField = type.DefineField("<Radius>k__BackingField", propertyType, FieldAttributes.Private);
var getter = type.DefineMethod("get_Radius", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName, propertyType, null);
var getterIl = getter.GetILGenerator();
getterIl.Emit(OpCodes.Ldarg_0);
getterIl.Emit(OpCodes.Ldfld, backingField);
getterIl.Emit(OpCodes.Ret);
radiusProperty.SetGetMethod(getter);
var setter = type.DefineMethod("set_Radius", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.SpecialName, null, new Type[] { propertyType });
var valueParameter = setter.DefineParameter(1, ParameterAttributes.None, "value");
var setterIl = setter.GetILGenerator();
setterIl.Emit(OpCodes.Ldarg_0);
setterIl.Emit(OpCodes.Ldarg_1);
setterIl.Emit(OpCodes.Stfld, backingField);
setterIl.Emit(OpCodes.Ret);
radiusProperty.SetSetMethod(setter);
Func<double> circleAreaExpression = () => Math.PI * Math.Pow((double)radiusProperty.GetValue(this), 2);
var or = new OperationReader(circleAreaExpression.Method);
var frame = new StackFrame();
var body = frame.GetMethod().GetMethodBody();
var locals = body.LocalVariables;

Inspecting intermediate language of the anonymous method shows that it contains Load Field radiusProperty operation, where radiusProperty is our newly created PropertyBuilder, preserved as a field of some anonymous class.

or.Operations {System.Reflection.Operation[11]} System.Reflection.Operation[]

+[0] {0000 : ldc.r81414344187}System.Reflection.Operation

+[1]{0009 : ldarg.0} System.Reflection.Operation

+[2]{0010 : ldfld System.Reflection.Emit.PropertyBuilder MethodTest.Program+<>c__DisplayClass0_0::radiusProperty}
System.Reflection.Operation

+[3]{0015 : ldarg.0} System.Reflection.Operation

+[4]{0016 : ldfld MethodTest.Program MethodTest.Program+<>c__DisplayClass0_0::<>4__this} System.Reflection.Operation

+[5]{0021 : callvirt instance System.Object System.Reflection.PropertyInfo::GetValue()}
System.Reflection.Operation

+[6] {0026 : unbox.any System.Double} System.Reflection.Operation

+[7] {0031 : ldc.r81073741824} System.Reflection.Operation

+[8] {0040 : call System.Double System.Math::Pow()} System.Reflection.Operation

+[9] {0045 : mul} System.Reflection.Operation

+[10] {0046 : ret} System.Reflection.Operation

What we would like to achieve now, is get our original PropertyBuilder, that it is a field of mentioned anonymous class. Browsing local variables of the method body that we are currently in shows, that the interesting anonymous class proudly holds the first position in local variables array. Although we do not have any reference to that anonymous class instance. Any tips how to get reference to the interesting PropertyBuilder?

locals Count = 19 System.Collections.Generic.IList {System.Collections.ObjectModel.ReadOnlyCollection}

+[0] {MethodTest.Program+<>c__DisplayClass0_0 (0)}
System.Reflection.LocalVariableInfo>

+[1] {System.Reflection.AssemblyName (1)}
System.Reflection.LocalVariableInfo

+[2] {System.AppDomain (2)} System.Reflection.LocalVariableInfo

+[3] {System.Reflection.Emit.AssemblyBuilder (3)} System.Reflection.LocalVariableInfo>

+[4] {System.Reflection.Emit.ModuleBuilder (4)}
System.Reflection.LocalVariableInfo>

+[5] {System.Type (5)} System.Reflection.LocalVariableInfo

+[6] {System.Reflection.Emit.TypeBuilder (6)}
System.Reflection.LocalVariableInfo

+[7] {System.Type (7)} System.Reflection.LocalVariableInfo

+[8] {System.Reflection.Emit.FieldBuilder (8)}
System.Reflection.LocalVariableInfo

+[9] {System.Reflection.Emit.MethodBuilder (9)}
System.Reflection.LocalVariableInfo

+[10] {System.Reflection.Emit.ILGenerator (10)}
System.Reflection.LocalVariableInfo

+[11] {System.Reflection.Emit.MethodBuilder (11)} System.Reflection.LocalVariableInfo

+[12] {System.Reflection.Emit.ParameterBuilder (12)}
System.Reflection.LocalVariableInfo

+[13] {System.Reflection.Emit.ILGenerator (13)}
System.Reflection.LocalVariableInfo

+[14] {System.Func``1[System.Double] (14)} System.Reflection.LocalVariableInfo

+[15] {System.Reflection.OperationReader (15)}
System.Reflection.LocalVariableInfo

+[16] {System.Diagnostics.StackFrame (16)} System.Reflection.LocalVariableInfo

+[17] {System.Reflection.MethodBody (17)} System.Reflection.LocalVariableInfo

+[18] {System.Collections.Generic.IList`1[System.Reflection.LocalVariableInfo] (18)} System.Reflection.LocalVariableInfo

Here are missing classes : link1 link2

MaLiN2223
  • 1,290
  • 3
  • 19
  • 40
  • How about skipping all of the reflection, making your method take a generic of your anoymous type and a `Func` so you can select the radius at the point of calling? – Matthew Whited Mar 14 '16 at 20:32

2 Answers2

1

I am not completely sure if this is what you want, but to get the PropertyBuilder instance out of the anonymous type is quite simple with reflection. Assuming there is only one field of this type you can use this code:

var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;
var pBuilder =
    circleAreaExpression.Target.GetType()
        .GetFields(flags)
        .Single(y => y.FieldType == typeof (PropertyBuilder))
        .GetValue(circleAreaExpression.Target);
thehennyy
  • 4,020
  • 1
  • 22
  • 31
  • Thank you very much! That was exactly what I was looking for. I just needed to get interesting PropertyBuilder value from FieldInfo variable that I already had in my IL operations table and pass circleAreaExpression.Target as anonymous type instance holding that FieldInfo. – MaLiN2223 Mar 15 '16 at 20:18
-1

Since you can't really be sure of the anoymous object's properties I'd suggest you move the method to select your property to a func that is being passed in with the object.

static void Main(string[] args)
{
    var area = ScaryMethod(new { rad = 3 }, t => t.rad);
}

public static double ScaryMethod<T>(T input, Func<T, double> radiusSelector)
{
    var radius = radiusSelector(input);
    return Math.PI * Math.Pow(radius, 2);
}

It's not really a good idea to rely on reflection.

Matthew Whited
  • 22,160
  • 4
  • 52
  • 69
  • The goal of this task is to make post processing of anonymous method IL. Resolving anonymus class is crutial as usages of those need to be replaced during the post procesing. Making static method instead anonymous one is not preffered solution. That is element of requirements. – MaLiN2223 Mar 14 '16 at 20:58
  • Hint, you can't do this reliable with reflection... but thanks for the downvote. The problem is your design. – Matthew Whited Mar 14 '16 at 21:11