找回密码
 立即注册
首页 业界区 安全 跟着AutoMapper学反射,你学会了吗?

跟着AutoMapper学反射,你学会了吗?

任静柔 7 天前
最近看AutoMapper源码,被1行代码震惊到了。
请各位工程师也look一下:
  1. private static readonly MethodInfo ContextMapMethod =
  2.     ExpressionFactory.Method<ResolutionContext, object>(a => a.Map<object, object>(null, null, null)).GetGenericMethodDefinition();
复制代码
看到这个代码本人震惊到了。
第一眼的反应是出bug了,测试代码写错地方了,那些object和null是认真的吗?
但直觉这不可能是bug!!!
 
一、赶紧测试一下
1. 于是把部分代码复制过来做了一个简单的测试
  1. public static MethodInfo Method<T>(Expression<Func<T>> expression) => GetExpressionBodyMethod(expression);
  2. public static MethodInfo Method<TType, TResult>(Expression<Func<TType, TResult>> expression) => GetExpressionBodyMethod(expression);
  3. private static MethodInfo GetExpressionBodyMethod(LambdaExpression expression) => ((MethodCallExpression)expression.Body).Method;
复制代码
  1. public static int Sqrt(int x)
  2.     => x * x;
  3. int x = 3;
  4. var sqrtMethod = Method<int, int>(x => Sqrt(x));
  5. var result = sqrtMethod.Invoke(null, [x]);<br>// result = 9
复制代码
不出意料,非常成功
2. 以前怎么反射方法呢
  1. var sqrtMethod0 = typeof(MyTests).GetMethod("Sqrt");
复制代码
3. 那两种方法哪种更好呢
初看原来的方法更简单,其实不然。
其一、原方法写死方法名
如果方法重命名,甚至增减参数,只有到运行时才报错,简直是埋了颗地雷啊
新方法就不一样了,重命名用vs重构就能直接适应
参数增、减可能会直接导致编译出错,以便及时处理
其二、如果方法有重载,更显得新方法的优势
  1. var sqrtMethod0 = typeof(MyTests).GetMethod("Sqrt", BindingFlags.Static | BindingFlags.Public, [typeof(int)]);
复制代码
方法有重载就需要提供参数类型列表和修饰符,新方法都不用,表达式就像用指针调用方法一样
 
二、这种方法还可以变通使用
1. 再建一个新的辅助方法
  1. public static MethodInfo GetActionMethodInfo<TArgument>(Expression> expression)
  2.     => GetExpressionBodyMethod(expression);
复制代码
2. 重写前面的例子
  1. var sqrtMethod2 = GetActionMethodInfo<int>(x => Sqrt(x));
复制代码
用Action的表达式反射Func,是不是很神奇
再结合.net的协变和逆变,能用更简单的方式构建调用方法的表达式
只要能构建一个调用方法的表达式就能反射出该方法
 
三、用表达式还可以反射属性、字段、索引器和构造函数等
 
通过.net表达式来反射是不是更优雅,今天的内容你学会了吗? 
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册