由于频繁地使用反射会影响性能,所以ASP.NET MVC采用了表达式树的方式来执行目标Action方法。具体来说,ASP.NET MVC会构建一个表达式来体现针对目标Action方法的执行,并且将该表达式编译成可执行代码。编译后的可执行代码体现为一个委托对象,该委托对象会被缓存起来以用于针对同一个Action方法的执行。为了让大家能够和直观地理解两种(直接利用反射和利用表达式编译后的委托对象)方法执行在性能上的差异,我们来做一个简单的实例演示。我们在一个控制台应用中定义了如下一个Foobar类型,它的Invoke方法就是我们需要测试的目标方法。简单起见,我们没有为它定义任何参数,方法本身也不需要执行任何具体操作。

   1: public class Foobar

   2: {

   3:     public void Invoke(){}

   4: }

具体的测试程序如下所示。三个静态属性Target、Method和Executor分别代表执行的目标对象、目标方法和表达式编译后生成的委托对象,后者通过调用静态方法CreateExecutor方法创建。

   1: class Program

   2: {

   3:  

   4:     public static Foobar Target { get; private set; }

   5:     public static MethodInfo Method { get; private set; }

   6:     public static Action<Foobar> Executor { get; private set; }

   7:  

   8:     private static object[] args = new object[0];

   9:  

  10:     private static Action<Foobar> CreateExecutor(MethodInfo method)

  11:     { 

  12:         ParameterExpression target = Expression.Parameter(typeof(Foobar),"target");

  13:         Expression expression = Expression.Call(target, method);

  14:         return Expression.Lambda<Action<Foobar>>(expression, target).Compile();

  15:     }

  16:  

  17:     static Program()

  18:     {

  19:         Target = new Foobar();

  20:         Method = typeof(Foobar).GetMethod("Invoke");

  21:         Executor = CreateExecutor(Method);

  22:     }

  23:  

  24:     static void Main()

  25:     {

  26:         Console.WriteLine("{0,-10}{1,-12}{2}", "Times", "Reflection", "Expression");

  27:         Test(100000);

  28:         Test(1000000);

  29:         Test(10000000);

  30:     }

  31:  

  32:     private static void Test(int times)

  33:     {

  34:         Stopwatch stopwatch = new Stopwatch();

  35:  

  36:         stopwatch.Start();           

  37:         for (int i = 0; i < times; i++)

  38:         {

  39:             Method.Invoke(Target, args);

  40:         }

  41:         long elapsed1 = stopwatch.ElapsedMilliseconds;           

  42:  

  43:         stopwatch.Restart();

  44:         for (int i = 0; i < times; i++)

  45:         {

  46:             Executor(Target);

  47:         }

  48:         long elapsed2 = stopwatch.ElapsedMilliseconds;

  49:  

  50:         Console.WriteLine("{0,-10}{1,-12}{2}", times, elapsed1, elapsed2);

  51:     }

  52: }

测试方法Test的参数times表示我们执行目标方法的次数。在该方法中,我们调用MethodInfo对象的Invoke方法以反射的形式执行目标方法,然后利用Executor属性表示的委托对象来执行目标方法,并将它们执行的时间(以毫秒为单位)输出来。在作为程序入口的Main方法中,我们先后三个调用Test方法,并将执行目标方法的次数分别设置为100,000(十万)、1,000,000(百万)和10,000,000(千万)。运行程序后我们会在控制台上得到如下所示的输出结果,可以看出直接采用反射方式执行某个方法确实在性能上要差一些,但是差异其实不算明显。很多人总是觉得在程序中使用反射会对性能造成很大的影响,其实在我看来在很多情况下反射本身都不是造成性能瓶颈的元凶。

   1: Times      Reflection     Expression

   2: 100000     34             2

   3: 1000000    273            28

   4: 10000000   2627           284

比较一下以“反射”和“表达式”执行方法的性能差异的更多相关文章

  1. js 将字符串当作js表达式执行方法

    听同事说了一个需求.他有一个数据对象obj,接口会给他返回一个索引key,这个key长度不固定,根据这个key去修改obj对应的值. 举个例子: let obj={"level1" ...

  2. 使用Java反射优化多个方法调用

    有段时间没来写博客了,心里一直念叨空了来,今天有时间来记录一篇.前段时间领导提出优化部分系统模块,根据业务要求系统中有很多产品,产品下面有N个指标,一个指标就对应一个方法,所以系统代码中就是这样一个情 ...

  3. CASE函数 sql server——分组查询(方法和思想) ref和out 一般处理程序结合反射技术统一执行客户端请求 遍历查询结果集,update数据 HBuilder设置APP状态栏

    CASE函数   作用: 可以将查询结果集的某一列的字段值进行替换 它可以生成一个新列 相当于switch...case和 if..else 使用语法: case 表达式/字段 when 值 then ...

  4. Java反射、动态加载(将java类名、方法、方法参数当做参数传递,执行方法)

    需求:将java类名.方法.方法参数当做参数传递,执行方法.可以用java的动态加载实现   反射的过程如下:     第一步:通过反射找到类并创建实例(classname为要实例化的类名,由pack ...

  5. Day16_88_通过反射机制执行方法

    通过反射机制执行方法 * method.invoke(object,"admin","123"); * 代码 import java.lang.reflect. ...

  6. kettle job如何利用java的反射机制获取执行的sql语句

    kettle job中的JavaScript如何获取同一个job中SQL步骤的执行语句并让执行语句记录在日志中呢?首先写日志需要用到job中JavaScript写日志的方法,其次是利用java反射机制 ...

  7. 通过spring来配置某个命令号和执行方法之间的映射

    整理的内容 1.手动获取spring的ApplicationContext和bean对象 写一个工具类实现ApplicationContextAware接口 2.反射的知识整理 3.前后端协议交互的时 ...

  8. day27:反射和双下方法

    1, # 面向对象的三大特性:继承,多态和封装 # 继承: # 单继承: **** # 父类(超类,基类) # 子类(派生类) 派生方法和派生属性 # 子类的对象在调用方法和属性:先用自己的,自己没有 ...

  9. Java 8-Lambda表达式、方法引用、标准函数接口与流操作、管道操作之间的关系

    1.Lambda表达式与接口之间的关系 只要Lambda表达式的声明形式与接口相一致,在很多情况下都可以替换接口.见如下代码 Thread t1 = new Thread(new Runnable() ...

随机推荐

  1. 【系统篇】从int 3探索Windows应用程序调试原理

    探索调试器下断点的原理 在Windows上做开发的程序猿们都知道,x86架构处理器有一条特殊的指令——int 3,也就是机器码0xCC,用于调试所用,当程序执行到int 3的时候会中断到调试器,如果程 ...

  2. Mac下搭建hexo

    Mac下搭建hexo 并部署到gitcafe 1.安装brewhome ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homeb ...

  3. HDu--我要拿走你的蜡烛

    我要拿走你的蜡烛 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  4. bfs判断连通图(无向)

    在图论中,连通图基于连通的概念.在一个无向图 G 中,若从顶点vi到顶点vj有路径相连(当然从vj到vi也一定有路径),则称vi和vj是连通的.如果 G 是有向图,那么连接vi和vj的路径中所有的边都 ...

  5. java并发编程(十七)内存操作总结

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17377197 主内存与工作内存 Java内存模型的主要目标是定义程序中各个变量的访问规则, ...

  6. 通过反射获取DLL的类实现加载窗体

    1.创建一个DLL 类库,并新建一个窗体类,这个直接在vs上操作就好 2. 建立一个Testassembly工程 新建一个测试类 namespace Testassembly { public par ...

  7. Android_SQLite数据库增删改查操作

    一:什么是SQLite? 在Android平台上,集成了一个嵌入式关系型轻量级的数据库. 二:什么时候用的数据库? 有大量相似机构的数据需要存储时. 三:如何创建一个数据库? 1.创建一个Sqlite ...

  8. Hadoop-1.2.1 升级到Hadoop-2.6.0 HA

      Hadoop-1.2.1到Hadoop-2.6.0升级指南   作者 陈雪冰 修改日期 2015-04-24 版本 1.0     本文以hadoop-1.2.1升级到hadoop-2.6.0 Z ...

  9. TCPView for Windows

    TCPView是一个用来显示系统中所有的TCP和UDP端点(endpoint)列表的Windows程序,包括本地和远程的网络地址,以及TCP连接的状态.在Windows Server 2008.Vis ...

  10. 嵌入式的重要平台 .NET Micro Framework

    曾经辉煌的巨人PC界渐渐走向下坡路,而智能手机圈则没完没了般地争个你死我活.随着智能手机的广泛普及,不少商家为了不坐以待毙而纷纷开始涉足与穿戴式设备--智能手表(具体参见智能手表时代还有多远). 我们 ...