首页 > 代码库 > 转鹤冲天兄反射性能比较
转鹤冲天兄反射性能比较
替代反射调用的几种方式及性能测试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 方法的动态调用:12 dynamic 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); // ExressionTreeFunc<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 的一些“新”特性。-------------------思想火花,照亮世界
转鹤冲天兄反射性能比较
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。