跟著AutoMapper學反射,你學會了嗎?
最近看AutoMapper源碼,被1行代碼震驚到了。
請各位工程師也look一下:
private static readonly MethodInfo ContextMapMethod = ExpressionFactory.Method<ResolutionContext, object>(a => a.Map<object, object>(null, null, null)).GetGenericMethodDefinition();
看到這個代碼本人震驚到了。
第一眼的反應是出bug了,測試代碼寫錯地方了,那些object和null是認真的嗎?
但直覺這不可能是bug!!!
一、趕緊測試一下
1. 于是把部分代碼復制過來做了一個簡單的測試
public static MethodInfo Method<T>(Expression<Func<T>> expression) => GetExpressionBodyMethod(expression); public static MethodInfo Method<TType, TResult>(Expression<Func<TType, TResult>> expression) => GetExpressionBodyMethod(expression); private static MethodInfo GetExpressionBodyMethod(LambdaExpression expression) => ((MethodCallExpression)expression.Body).Method;
public static int Sqrt(int x) => x * x; int x = 3; var sqrtMethod = Method<int, int>(x => Sqrt(x)); var result = sqrtMethod.Invoke(null, [x]);
// result = 9
不出意料,非常成功
2. 以前怎么反射方法呢
var sqrtMethod0 = typeof(MyTests).GetMethod("Sqrt");
3. 那兩種方法哪種更好呢
初看原來的方法更簡單,其實不然。
其一、原方法寫死方法名
如果方法重命名,甚至增減參數,只有到運行時才報錯,簡直是埋了顆地雷啊
新方法就不一樣了,重命名用vs重構就能直接適應
參數增、減可能會直接導致編譯出錯,以便及時處理
其二、如果方法有重載,更顯得新方法的優勢
var sqrtMethod0 = typeof(MyTests).GetMethod("Sqrt", BindingFlags.Static | BindingFlags.Public, [typeof(int)]);
方法有重載就需要提供參數類型列表和修飾符,新方法都不用,表達式就像用指針調用方法一樣
二、這種方法還可以變通使用
1. 再建一個新的輔助方法
public static MethodInfo GetActionMethodInfo<TArgument>(Expression<Action<TArgument>> expression) => GetExpressionBodyMethod(expression);
2. 重寫前面的例子
var sqrtMethod2 = GetActionMethodInfo<int>(x => Sqrt(x));
用Action的表達式反射Func,是不是很神奇
再結合.net的協變和逆變,能用更簡單的方式構建調用方法的表達式
只要能構建一個調用方法的表達式就能反射出該方法
三、用表達式還可以反射屬性、字段、索引器和構造函數等
通過.net表達式來反射是不是更優雅,今天的內容你學會了嗎?
浙公網安備 33010602011771號