推荐一个快速反射调用的类

本文转载:http://blog.csdn.net/jehnjehn/article/details/7086863

 

使用传统的.net反射机制,调用类的方法时,在调用频率大的情况下,会感觉速度很慢。最近浏览卢彦的博客时,找到一个他改进后的反射调用类。试用以后感觉效率明显提高,特推荐给大家。作者重新实现了,反射调用方法,但是调用接口和.net原有方法一致。而且调用时抛出的异常为所调用类的实际异常,不像传统方式返回为包装异常。
文章来源:http://www.codeproject.com/csharp/FastMethodInvoker.asp

快速反射调用类

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace FastMethodInvoker
{
    class FastInvoke
    {
        publicdelegateobject FastInvokeHandler(object target, object[] paramters);

        staticobject InvokeMethod(FastInvokeHandler invoke, object target, paramsobject[] paramters)
        {
            return invoke(null, paramters);
        }

        publicstatic FastInvokeHandler GetMethodInvoker(MethodInfo methodInfo)
        {
            DynamicMethod dynamicMethod =new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo.DeclaringType.Module);
            ILGenerator il = dynamicMethod.GetILGenerator();
            ParameterInfo[] ps = methodInfo.GetParameters();
            Type[] paramTypes =new Type[ps.Length];
            for (int i =0; i < paramTypes.Length; i++)
            {
                if (ps[i].ParameterType.IsByRef)
                    paramTypes[i] = ps[i].ParameterType.GetElementType();
                else
                    paramTypes[i] = ps[i].ParameterType;
            }
            LocalBuilder[] locals =new LocalBuilder[paramTypes.Length];

            for (int i =0; i < paramTypes.Length; i++)
            {
                locals[i] = il.DeclareLocal(paramTypes[i], true);
            }
            for (int i =0; i < paramTypes.Length; i++)
            {
                il.Emit(OpCodes.Ldarg_1);
                EmitFastInt(il, i);
                il.Emit(OpCodes.Ldelem_Ref);
                EmitCastToReference(il, paramTypes[i]);
                il.Emit(OpCodes.Stloc, locals[i]);
            }
            if (!methodInfo.IsStatic)
            {
                il.Emit(OpCodes.Ldarg_0);
            }
            for (int i =0; i < paramTypes.Length; i++)
            {
                if (ps[i].ParameterType.IsByRef)
                    il.Emit(OpCodes.Ldloca_S, locals[i]);
                else
                    il.Emit(OpCodes.Ldloc, locals[i]);
            }
            if (methodInfo.IsStatic)
                il.EmitCall(OpCodes.Call, methodInfo, null);
            else
                il.EmitCall(OpCodes.Callvirt, methodInfo, null);
            if (methodInfo.ReturnType ==typeof(void))
                il.Emit(OpCodes.Ldnull);
            else
                EmitBoxIfNeeded(il, methodInfo.ReturnType);

            for (int i =0; i < paramTypes.Length; i++)
            {
                if (ps[i].ParameterType.IsByRef)
                {
                    il.Emit(OpCodes.Ldarg_1);
                    EmitFastInt(il, i);
                    il.Emit(OpCodes.Ldloc, locals[i]);
                    if (locals[i].LocalType.IsValueType)
                        il.Emit(OpCodes.Box, locals[i].LocalType);
                    il.Emit(OpCodes.Stelem_Ref);
                }
            }

            il.Emit(OpCodes.Ret);
            FastInvokeHandler invoder = (FastInvokeHandler)dynamicMethod.CreateDelegate(typeof(FastInvokeHandler));
            return invoder;
        }

        privatestaticvoid EmitCastToReference(ILGenerator il, System.Type type)
        {
            if (type.IsValueType)
            {
                il.Emit(OpCodes.Unbox_Any, type);
            }
            else
            {
                il.Emit(OpCodes.Castclass, type);
            }
        }

        privatestaticvoid EmitBoxIfNeeded(ILGenerator il, System.Type type)
        {
            if (type.IsValueType)
            {
                il.Emit(OpCodes.Box, type);
            }
        }

        privatestaticvoid EmitFastInt(ILGenerator il, int value)
        {
            switch (value)
            {
                case-1:
                    il.Emit(OpCodes.Ldc_I4_M1);
                    return;
                case0:
                    il.Emit(OpCodes.Ldc_I4_0);
                    return;
                case1:
                    il.Emit(OpCodes.Ldc_I4_1);
                    return;
                case2:
                    il.Emit(OpCodes.Ldc_I4_2);
                    return;
                case3:
                    il.Emit(OpCodes.Ldc_I4_3);
                    return;
                case4:
                    il.Emit(OpCodes.Ldc_I4_4);
                    return;
                case5:
                    il.Emit(OpCodes.Ldc_I4_5);
                    return;
                case6:
                    il.Emit(OpCodes.Ldc_I4_6);
                    return;
                case7:
                    il.Emit(OpCodes.Ldc_I4_7);
                    return;
                case8:
                    il.Emit(OpCodes.Ldc_I4_8);
                    return;
            }

            if (value >-129&& value <128)
            {
                il.Emit(OpCodes.Ldc_I4_S, (SByte)value);
            }
            else
            {
                il.Emit(OpCodes.Ldc_I4, value);
            }
        }
    }
}

效果测试程序

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace FastMethodInvoker
{
    class Program
    {
        staticvoid Main(string[] args)
        {

            Type t =typeof(Person);
            MethodInfo methodInfo = t.GetMethod("Say");
            Person person =new Person();
            string word ="hello";
            Person p =null;
            object[] param =newobject[] { word, p, 3 };
            int TestTimes =100000; //测试次数,可自行调节看效果

            #region 传统方式反射
            try
            {
                Stopwatch watch =new Stopwatch();
                watch.Start();
                for (int i =0; i < TestTimes; i++)
                {
                    methodInfo.Invoke(person, param);
                }
                watch.Stop();
                Console.WriteLine(TestTimes.ToString() +" times invoked by Reflection: "+ watch.ElapsedMilliseconds +"ms");
            }
            catch (System.Exception ex)
            {
                Console.WriteLine("传统方式反射 直接错误:"+ ex.Message);
                Console.WriteLine("传统方式反射 内部错误:"+ ex.InnerException.Message);
            }
            #endregion

            #region 快速反射
            try
            {
                Stopwatch watch1 =new Stopwatch();
                FastInvoke.FastInvokeHandler fastInvoker = FastInvoke.GetMethodInvoker(methodInfo);
                watch1.Start();
                for (int i =0; i < TestTimes; i++)
                {
                    fastInvoker(person, param);
                }
                watch1.Stop();
                Console.WriteLine(TestTimes.ToString() +" times invoked by FastInvoke: "+ watch1.ElapsedMilliseconds +"ms");
            }
            catch (System.Exception ex)
            {
                Console.WriteLine("快速反射 错误:"+ ex.Message);
            }
            #endregion

            #region 直接调用
            try
            {
                Stopwatch watch2 =new Stopwatch();
                watch2.Start();
                for (int i =0; i < TestTimes; i++)
                {
                    person.Say(ref word, out p, 3);
                }
                watch2.Stop();
                Console.WriteLine(TestTimes.ToString() +" times invoked by DirectCall: "+ watch2.ElapsedMilliseconds +"ms");
            }
            catch (System.Exception ex)
            {
                Console.WriteLine("直接调用 错误:"+ ex.Message);
            }
            #endregion
           
            Console.ReadLine();
        }
    }

    publicclass Person
    {
        publicvoid Say(refstring word, out Person p, int avi)
        {
            word ="ttt"+ avi.ToString();
            p =new Person();

            //throw new System.Exception("出错了哦");
        }
    }
}

时间: 2024-11-01 04:56:25

推荐一个快速反射调用的类的相关文章

spring-通过类反射调用的类中,通过Spring @Autowired 装载失败

问题描述 通过类反射调用的类中,通过Spring @Autowired 装载失败 使用了@Autowired注释,自动装配成员变量,正常情况下没有问题,但是当这个类通过java的反射机制调用时,自动装配失败,成员变量时空值,出现空指针异常. 解决方案 已经解决了,不过觉得破坏了框架,可能真的没法办法吧,现在贴出来我自己解决的办法 //手动注入,防止反射无法注入 private void ManulInject(){ ApplicationContext apx=new ClassPathXmlA

如何通过反射调用普通类中的泛型方法?(有重载)

问题描述 usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Reflection;namespace复习{classProgram{staticvoidMain(string[]args){Typet1=typeof(Person);MethodInfomi1=t1.GetMethod("SayHello",BindingFlags.NonPublic|Bi

CYQ.Data V4.5.5 版本发布[顺带开源Emit编写的快速反射转实体类FastToT类]

前言:   继上一版本:CYQ.Data 数据框架 版本发布 V4.5,刷的一下又三个多月了, 进一步的说,从 CYQ.Data V4.5的发布到现在,是半年多了,今天,终于得发布新小版本了. 由于上一版本过于稳定,导致此版本无bug修正项,但是新增了几个重要的性能优化功能.   本版本新增加的功能预览   1:优化Access.SQLite数据库链接,以{0}代表根目录 好处:可以配置多个数据库链接,示例如:秋色园QBlog同时用了N个access数据库.   2:MAction增加指定列的查

Java反射高级应用--利用反射调用类的私有方法修改私有方法值,以及替换Java的类成员数据

  package me.test; import java.lang.reflect.*;  //导入反射需要的包 public class ReflectTest {  public static void main(String[] args)  throws  Exception  {       /*  下面通过反射完成对一个对象中成员的替换    *   并且执行执行私有方法     *   完成对 Poiont类的对象中所有的 String的对象的d换成x    *   并且类中无

推荐一个简单的托盘类

有的网友开发了自己的托盘类,实现起来略微烦琐.在这里我向大家推荐一个实现简单而十分有效的托盘类(是我在一本书中学来的). 1.把TrayIcon.cpp和TrayIcon.cpp拷贝到你的项目目录,并添加到项目中. 2.在DemoDlg.h中加入#include "TrayIcon.h" 3.通过类向导向类CDemoDlg添加成员变量CTrayIcon m_CTrayIcon; 4.建立菜单资源,使其ID为:IDR_DEMO,设计菜单: 向demo1和exit添加事件处理程序: voi

调用-自己写的一个php的PDO的类,有点问题,求大神指点

问题描述 自己写的一个php的PDO的类,有点问题,求大神指点 自己写的一个php的PDO的类,在调用的时候可以查询,插入的时候没有报错,但是插入没有成功,这是怎么回事.......... 这个是调用的类 <?php header("content-type:text/html;charset=utf-8"); class dbPdoManger { private $conn='';//连接数据库服务器的资源类型 private $host="";//主机地

java-spring中配置了一个系统调度控制器调用类shop_stat 启动报错

问题描述 spring中配置了一个系统调度控制器调用类shop_stat 启动报错 spring配置文件 applicationContext-configuration.xml 配置如下: <!-- 系统调度控制器 --> <bean id="statTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <!--

ios-iOS 求推荐一个可在线听歌且可写入缓存的音乐类 谢谢

问题描述 iOS 求推荐一个可在线听歌且可写入缓存的音乐类 谢谢 如题 我发现大部分开源的音乐播放库 基本都是在线听歌 却没有边听边写入缓存的 求推荐 还是我理解 有误 我的目的是 首先我的UI会是一个tableview的列表 然后我会去搜索歌 一开始列表为空 此时从搜索去听歌 这时就是在线听歌 并缓存这首歌 下次即使没网也可以听上次那首歌 先谢谢了 在线等 解决方案 code4上面应该有,你去看看. 解决方案二: 你用什么?请求数据的,找一个带缓存的AFNetWorking 然后根据自己的需求

javascript-js类中一个方法无法调用弄一个方法

问题描述 js类中一个方法无法调用弄一个方法 <!DOCTYPE html> <html> <head> <title></title> </head> <body> <script type="text/javascript"> function ui(){ this.we=function(){ alert("wed"); } this.test=function(e