• (译)一个通用快速的反射方法调用


     

    原文:http://www.codeproject.com/Articles/14593/A-General-Fast-Method-Invoker

     

    源码下载:示例代码_for_一个通用快速的反射方法调用

    image

    介绍

             有时,我们会碰见需要动态调用对象方法的场景,而这个方法只有在运行的时候才能得知。通常的,会使用方法的反射调用,但是这通常会导致程序速度变慢。这篇文章将介绍一种高效替代方案----动态方法调用。

     

    背景环境

             当我读到文章Fast Dynamic Property Accessors时,我想到我项目中在循环中运用了大量方法的反射调用,然而这样调用是毫无效率的。DynamicMethod 提醒我是否可在方法调用前使用 System.Reflection.Emit 生成DynamicMethod绑定到指定的方法,这样或许能提高程序性能。

     

    代码

    首先,使用反射找到将要调用的方法成员:

      MethodInfo methodInfo = typeof(Person).GetMethod("Say");

    然后,创建动态方法并且返回调用该动态方法的委托:

      FastInvokeHandler fastInvoker = GetMethodInvoker(methodInfo);
      fastInvoker(new Person(), new object[]{"hello"});

    代替之前方法的反射调用:

      methodInfo.Invoke(new Person(), new object[]{"hello"});

     

    实现

    首先,我们需要为动态方法定义一个适当的委托:

    public delegate object FastInvokeHandler(object target, object[] paramters);

    为了不改变之前方法的反射调用模式,所以我们定义的委托接收参数和返回值类似MethodInfo.invoke()

             下面贴出 DynamicMethod 生成代码:

    public static 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++)
        {
            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]);
        }
        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]);
        }
        il.Emit(OpCodes.Ldarg_0);
        for (int i = 0; i < paramTypes.Length; i++)
        {
            il.Emit(OpCodes.Ldloc, locals[i]);
        }
        il.EmitCall(OpCodes.Call, methodInfo, null);
        if (methodInfo.ReturnType == typeof(void))
            il.Emit(OpCodes.Ldnull);
        else
            EmitBoxIfNeeded(il, methodInfo.ReturnType);
        il.Emit(OpCodes.Ret);
        FastInvokeHandler invoder = 
          (FastInvokeHandler)dynamicMethod.CreateDelegate(typeof(FastInvokeHandler));
        return invoder;
    }

     

    总结        

             好了,我想这个通用方法可以代替大多数方法的反射同时会获得大约50倍的效率提高,欢迎反馈任何改善的建议。

             另外值得注意的优势(感谢MaxGuernsey的提醒):如果你调用的方法内部抛出异常,FastInovker 会抛出具体错误信息,然而Method.Invoke 仅仅只会抛出“调用目标发生异常(TargetInvocationException)”。

     

             整理了一篇文章对该篇进行补充及扩展,欢迎查看《《(译)一个通用快速的反射方法调用》续篇》

     

    作者:Luyan

     

          相关链接:

                       《(9)程序集的加载和反射》

  • 相关阅读:
    手动创建DataSet数据集
    Ado.Net 参数化操作
    序列化和反序列化
    封装多个集合在一个类中
    窗体之间的传递
    C程序设计语言练习题1-12
    C程序设计语言练习题1-11
    C程序设计语言练习题1-10
    C程序设计语言练习题1-9
    C程序设计语言练习题1-8
  • 原文地址:https://www.cnblogs.com/heyuquan/p/2430720.html
Copyright © 2020-2023  润新知