访问权限自动创建匿名类型字段

时间:2016-03-14 19:47:50

标签: c# .net reflection emit

让我们成像,我们发出一个代表圆的类。我们定义一个表示其半径的double属性,以及相关的后备字段和get / set访问器。然后我们使用新创建的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;

检查匿名方法的中间语言表明它包含Load Field radiusProperty操作,其中 radiusProperty是我们新创建的PropertyBuilder,保留为某个匿名类的字段。

  

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 +&lt;&gt; c__DisplayClass0_0 :: radiusProperty}
  System.Reflection.Operation

     

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

     

+ [4] {0016:ldfld MethodTest.Program MethodTest.Program +&lt;&gt; c__DisplayClass0_0 ::&lt;&gt; 4__this}   System.Reflection.Operation

     

+ [5] {0021:callvirt实例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

我们现在想要实现的是获取我们原始的PropertyBuilder,它是一个提到的匿名类的字段。浏览我们当前所在的方法体的局部变量,即有趣的匿名类自豪地保持局部变量数组中的第一个位置。虽然我们没有任何对该匿名类实例的引用。 有关如何引用有趣的PropertyBuilder 的任何提示?

  

当地人数= 19   System.Collections.Generic.IList   {System.Collections.ObjectModel.ReadOnlyCollection}

     

+ [0] {MethodTest.Program +&lt;&gt; c__DisplayClass0_0(0)}
  System.Reflection.LocalVariableInfo&gt;

     

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

     

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

     

+ [3] {System.Reflection.Emit.AssemblyBuilder(3)}   System.Reflection.LocalVariableInfo&GT;

     

+ [4] {System.Reflection.Emit.ModuleBuilder(4)}
  System.Reflection.LocalVariableInfo&GT;

     

+ [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

以下是缺少的课程: link1 link2

2 个答案:

答案 0 :(得分:1)

我不完全确定这是否是您想要的,但是通过反射将PropertyBuilder实例从匿名类型中取出非常简单。假设只有一个这种类型的字段,您可以使用以下代码:

var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;
var pBuilder =
    circleAreaExpression.Target.GetType()
        .GetFields(flags)
        .Single(y => y.FieldType == typeof (PropertyBuilder))
        .GetValue(circleAreaExpression.Target);

答案 1 :(得分:-1)

由于您无法确定无聊对象的属性,我建议您移动方法以选择属性为与对象传入的func。

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

依靠反思并不是一个好主意。