跟着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, );<br>// result = 9不出意料,非常成功
2. 以前怎么反射方法呢
var sqrtMethod0 = typeof(MyTests).GetMethod("Sqrt");3. 那两种方法哪种更好呢
初看原来的方法更简单,其实不然。
其一、原方法写死方法名
如果方法重命名,甚至增减参数,只有到运行时才报错,简直是埋了颗地雷啊
新方法就不一样了,重命名用vs重构就能直接适应
参数增、减可能会直接导致编译出错,以便及时处理
其二、如果方法有重载,更显得新方法的优势
var sqrtMethod0 = typeof(MyTests).GetMethod("Sqrt", BindingFlags.Static | BindingFlags.Public, );方法有重载就需要提供参数类型列表和修饰符,新方法都不用,表达式就像用指针调用方法一样
二、这种方法还可以变通使用
1. 再建一个新的辅助方法
public static MethodInfo GetActionMethodInfo<TArgument>(Expression> expression)
=> GetExpressionBodyMethod(expression);2. 重写前面的例子
var sqrtMethod2 = GetActionMethodInfo<int>(x => Sqrt(x));用Action的表达式反射Func,是不是很神奇
再结合.net的协变和逆变,能用更简单的方式构建调用方法的表达式
只要能构建一个调用方法的表达式就能反射出该方法
三、用表达式还可以反射属性、字段、索引器和构造函数等
通过.net表达式来反射是不是更优雅,今天的内容你学会了吗?
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]