替代反射调用的几种方式及性能测试
2013-03-31 17:25 by 鹤冲天, 6065 阅读, 21 评论, 收藏, 编辑园子里和这个话题的相关文章比较多,本文是旧话重提,外加个小的总结。主要因为近期看到很多同事、朋友都已经使用 VS2012 进行 .NET 4.5 开发了,却还在大量使用反射,不知道用新的方式。或有所了解,但又害怕性能不好不敢大胆去用。本文以如下类为例:
public class MyMath
{public int Add(int a, int b){return a + b;}
}替代反射的几种方式倒序说吧,从最先进最简单的开始。1. dynamic 调用.NET 4 引入了 dynamic 类型,可以使用如下方式来完成对 MyMath.Add 方法的动态调用:1
2dynamic math = new MyMath();
int result = math.Add(1, 2);非常简单,效率也不错,可以看后面的性能对比测试结果。但有一点要注意, dynamic 遵守 .NET 的访问级别限定,会对成员进行可见性检查。也就是说,只能 dynamic 调用 public 成员;当然,如果是同一程序集内部,internal 成员也是可以访问的。2. Expression Tree 编译调用Expression Tree 是 .NET 3.5 引入的。简单地,我们可以使用 lambda 构建一颗 Expression Tree: var math = new MyMath();
Expression<Func<int, int, int>> add = (a, b) => math.Add(a, b);这种方法适合手工编码构建,还有另外一种方式可以动态构建:
var add = typeof(MyMath).GetMethod("Add");
var math = Expression.Parameter(typeof(MyMath));
var a = Expression.Parameter(typeof(int), "a");
var b = Expression.Parameter(typeof(int), "b");
var body = Expression.Call(myMath, add, a, b);
var lambda = Expression.Lambda<Func<MyMath, int, int, int>>(body, math, a, b);两种方式构建出的 Tree 是相同的。话归正题,构建出表达式树后,调用其 Compile 方法便可编译成一个委托,如下代码第 3 行:var math = new MyMath();
Expression<Func<int, int, int>> addExpTree = (a, b) => math.Add(a, b);  // ExressionTree
Func<int, int, int> add = addExpTree.Compile();                         //  编译成委托
var result = add(1, 2);                                                 // 相加,结果为3
 与 dynamic 调用方法同,Expression Tree 编译出的委托方法也遵守 .NET 的访问级别限定,会对成员进行可见性检查,不能访问私有成员。3. 反射发出调用这里只介绍反射发出的一项技术 DynamicMethod,.NET 2.0 新增此类。使用 DynamicMethod 类在运行时定义轻量全局方法,然后使用委托执行这些方法。针对 MyMath.Add 方法,调用比前面两种方式复杂些:
using System;
using System.Linq.Expressions;
using System.Reflection.Emit;public class MyMath {public int Add(int a, int b) { return a + b; }
}class Program {static void Main(string[] args) {int result;var math = new MyMath();var count = 1000000;Console.WriteLine("数据量:" + count);Console.WriteLine("-----------------------------r\n");using (Profiler.Step("循环:{0} ms")) {for (int i = 0; i < count; i++)result = 1;}using (Profiler.Step("直接调用 :{0} ms")) {for (int i = 0; i < count; i++)result = math.Add(i, i);}using (Profiler.Step("反射发出:{0} ms")) {var emitAdd = BuildEmitAddFunc();for (int i = 0; i < count; i++)result = emitAdd(math, i, i);}using (Profiler.Step("表达式树:{0} ms")) {var expressionAdd = BuildExpressionAddFunc();for (int i = 0; i < count; i++)result = expressionAdd(math, i, i);}using (Profiler.Step("dynamic 调用:{0} ms")) {dynamic d = math;for (int i = 0; i < count; i++)result = d.Add(i, i);}using (Profiler.Step("反射调用:{0} ms")) {var add = typeof(MyMath).GetMethod("Add");for (int i = 0; i < count; i++)result = (int)add.Invoke(math, new object[] { i, i });}Console.WriteLine("\r\n\r\n测试完成,任意键退出...");Console.ReadKey();}static Func<MyMath, int, int, int> BuildExpressionAddFunc() {var add = typeof(MyMath).GetMethod("Add");var math = Expression.Parameter(typeof(MyMath));var a = Expression.Parameter(typeof(int), "a");var b = Expression.Parameter(typeof(int), "b");var body = Expression.Call(math, add, a, b);var lambda = Expression.Lambda<Func<MyMath, int, int, int>>(body, math, a, b);return lambda.Compile();}static Func<MyMath, int, int, int> BuildEmitAddFunc() {var add = typeof(MyMath).GetMethod("Add");var dynamicMethod = new DynamicMethod("", typeof(int), new[] { typeof(MyMath), typeof(int), typeof(int) });var il = dynamicMethod.GetILGenerator();il.Emit(OpCodes.Ldarg_0);il.Emit(OpCodes.Ldarg_1);il.Emit(OpCodes.Ldarg_2);il.Emit(OpCodes.Callvirt, add);il.Emit(OpCodes.Ret);return (Func<MyMath, int, int, int>)dynamicMethod.CreateDelegate(typeof(Func<MyMath, int, int, int>));}
}Profiler 是我写的一个类,用于简化测试:using System;
using System.Diagnostics;public class Profiler : IDisposable {private Stopwatch watch;private string message;private Profiler(string message) {this.watch = new Stopwatch();this.watch.Start();this.message = message;}public void Dispose() {watch.Stop();Console.WriteLine(message, watch.ElapsedMilliseconds);Console.WriteLine();}public static IDisposable Step(string message) {return new Profiler(message);}public static T Inline<T>(string message, Func<T> func) {using (new Profiler(message))return func();}
}总结综上所述,我们可以使用 .NET 2.0 的 DynamicMethod,.NET 3.5 引入的 Expression Tree、.NET 4 新增的 dynamic 来替换反射调用,带来更好的性能。希望本文对大家有所帮助,也希望整天忙于项目、疲于工作的朋友抽点时间学习下 .NET Framework 的一些“新”特性。-------------------思想火花,照亮世界

转载于:https://www.cnblogs.com/feige/p/6352241.html

转鹤冲天兄反射性能比较相关推荐

  1. c 与java 反射性能_谈谈Java 反射的快慢

    [相关学习推荐:java基础教程] 反射到底是好是坏 说到Java 中的反射,初学者在刚刚接触到反射的各种高级特性时,往往表示十分兴奋,甚至会在一些不需要使用反射的场景中强行使用反射来「炫技」.而经验 ...

  2. 优化反射性能的总结(上)

    原文链接:http://www.cnblogs.com/fish-li/archive/2013/02/18/2916253.html 优化反射性能的总结(上) 阅读目录 开始 用Emit方法优化反射 ...

  3. java 提高反射性能_java反射性能

    项目中用到了java的反射,可以大大减少代码量.但是反射的性能却不容乐观,做了个简单的测试,如下. public void noreflect() { Person p = new Person(); ...

  4. Java反射性能探讨

    文章目录 反射是否影响性能 为什么反射影响性能 method.invoke & field.set 性能 Class.getMethod & Class.getDeclareField ...

  5. java 反射 性能_java高性能反射及性能对比

    java编程中,使用反射来增强灵活性(如各类框架).某些抽象(如各类框架)及减少样板代码(如Java Bean). 因此,反射在实际的java项目中被大量使用. 由于项目里存在反射的性能瓶颈,使用的是 ...

  6. 对对象类型和调用方法属性进行存储以提升反射性能

    反射的性能差是一个公认的事实.而最耗性能的还是根据程序集获取要调用的对象,而在对象里搜索要调用的方法所耗性能到不不是很多,如果对象里的方法不是特别的多,而去可以指定相关参数提高搜索的效率,比如Bind ...

  7. mvel 调用java_java MVEL2/Spring EL表达式、直接调用、反射性能实测

    importjava.io.Serializable;importjava.lang.reflect.Field;importjava.util.HashMap;importjava.util.Map ...

  8. java反射性能问题_Java反射应用实例java反射的性能问题 | 学步园

    很多IOC等框架都使用反射来实现,例如Spring, Hibernate等, Java反射的方式实现的逻辑比普通类逻辑的效率是要差一些的(14至300倍左右), 具体可以参考我转载的一篇文章< ...

  9. TableauBDP,哪个才是最适合中国用户的数据可视化分析工具?

    作者:pledge 本人数据分析师一枚,除了工作所需,自己对数据分析.数据可视化的产品工具都比较感兴趣,喜欢混迹于各种数据论坛,也发现和使用了不少数据工具,也积累了很多亲身经历.这两年数据可视化在国内 ...

最新文章

  1. MySQL 的 Binlog 日志处理工具(Canal/Maxwell/Databus/DTS)对比
  2. 多线程生成随机数组+多线程快速排序(C++实现)
  3. Hadoop教程(五):Flume、Sqoop、Pig、Hive、OOZIE
  4. js中如何通过身份证号计算出生日期和年龄
  5. SAP CRM Fiori Launchpad 登录之后,看不见任何 tile 的解决办法
  6. 使用vert.x 2.0,RxJava和mongoDB创建simpe RESTful服务
  7. 美团大脑:知识图谱的建模方法及其应用
  8. python切片逆序_Python 的逆序同时切片如何操作?
  9. UIAutomator2
  10. ubuntu切换用户root时认证失败
  11. PRINCE2认证之项目四大管理步骤
  12. matlab 批量取消注释,MATLAB中多行注释以及取消的快捷键
  13. 常见Andriod游戏破解搜索关键字
  14. 从今起,我蹲马步,苦练基本功
  15. 查看HP小型机的信息的命令集
  16. 激光功率的测量方案和设备
  17. 不再年轻的我,终于读懂了成年人的世界,就没有“容易”二字
  18. 安装完Ubuntu 18.04之后要做的几件事
  19. DSP、SSP、RTB、ADX、DMP(概念通俗解释)
  20. 白帽汇赵武:我们来聊一聊实名制

热门文章

  1. cad打开卡死_CAD启动时闪退怎么办?打开CAD就死机怎么办?
  2. flink学习(五)DataStream API
  3. 【笔记】C++ 命令行小游戏 节奏大师(别踩白块) 的制作
  4. 我们如何获取信息,组织知识
  5. 1650显卡学计算机,1650ti显卡属于什么档次?
  6. Docker基础、进阶笔记,为k8s的学习预预热
  7. jqGrid----下拉列表框下拉联动,dataEvents回调函数。
  8. 2020Android不死我不倒,作为一个程序员,你觉得最大的悲哀是什么?
  9. javascript技巧收集(200多个)
  10. apple帐号登录服务器端接入