2016-03-14 68 views
0

讓我們成像,我們發出一個代表圓的類。我們定義一個代表其半徑的雙重屬性,並且關聯後臺字段和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; 

檢查匿名方法的中間語言表明,它含有加載現場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 + <> c__DisplayClass0_0 :: radiusProperty}
系統。 Reflection.Operation

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

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

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

+ [6] {0026:拆箱.any System.Double} System.Reflection.Operat離子

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

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

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

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

我們想什麼,現在來實現的,是得到我們的原始PropertyBuilder,它是一個提到匿名類的領域。瀏覽我們當前所在方法體的局部變量,顯示有趣的匿名類自豪地擁有局部變量數組中的第一個位置。雖然我們沒有任何對這個匿名類實例的引用。 任何提示如何獲得有趣的PropertyBuilder的參考?

當地人計數= 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)}
系統。 Reflection.LocalVa riableInfo>

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

+0

如何跳過所有的反射,使你的方法需要一個通用的anoymous類型和'Func鍵的'所以你可以選擇呼叫時的半徑? –

回答

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

非常感謝!那正是我所期待的。我只需要從我的IL操作表中已有的FieldInfo變量中獲取有趣的PropertyBuilder值,並將circleAreaExpression.Target作爲匿名類型實例持有FieldInfo。 – MaLiN2223

-1

既然你不能真的相信了anoymous對象的屬性我建議你移動的方法來選擇你的財產的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); 
} 

依靠反思並不是一個好主意。

+0

此任務的目標是進行匿名方法IL的後處理。解析匿名類是非常重要的,因爲在後處理過程中需要替換那些類的用法。使用靜態方法而不是匿名方法不是優先選擇的解決方案。這是要求的要素。 – MaLiN2223

+0

提示,你不能用反射來做到這一點......但感謝downvote。問題在於你的設計。 –