zoukankan      html  css  js  c++  java
  • 推荐一个快速反射调用的类

    使用传统的.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
        
    {
            
    public delegate object FastInvokeHandler(object target, object[] paramters);

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


            
    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++)
                
    {
                    
    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;
            }


            
    private static void EmitCastToReference(ILGenerator il, System.Type type)
            
    {
                
    if (type.IsValueType)
                
    {
                    il.Emit(OpCodes.Unbox_Any, type);
                }

                
    else
                
    {
                    il.Emit(OpCodes.Castclass, type);
                }

            }


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

            }


            
    private static void EmitFastInt(ILGenerator il, int value)
            
    {
                
    switch (value)
                
    {
                    
    case -1:
                        il.Emit(OpCodes.Ldc_I4_M1);
                        
    return;
                    
    case 0:
                        il.Emit(OpCodes.Ldc_I4_0);
                        
    return;
                    
    case 1:
                        il.Emit(OpCodes.Ldc_I4_1);
                        
    return;
                    
    case 2:
                        il.Emit(OpCodes.Ldc_I4_2);
                        
    return;
                    
    case 3:
                        il.Emit(OpCodes.Ldc_I4_3);
                        
    return;
                    
    case 4:
                        il.Emit(OpCodes.Ldc_I4_4);
                        
    return;
                    
    case 5:
                        il.Emit(OpCodes.Ldc_I4_5);
                        
    return;
                    
    case 6:
                        il.Emit(OpCodes.Ldc_I4_6);
                        
    return;
                    
    case 7:
                        il.Emit(OpCodes.Ldc_I4_7);
                        
    return;
                    
    case 8:
                        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
        
    {
            
    static void Main(string[] args)
            
    {

                Type t 
    = typeof(Person);
                MethodInfo methodInfo 
    = t.GetMethod("Say");
                Person person 
    = new Person();
                
    string word = "hello";
                Person p 
    = null;
                
    object[] param = new object[] { 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();
            }

        }


        
    public class Person
        
    {
            
    public void Say(ref string word, out Person p, int avi)
            
    {
                word 
    = "ttt" + avi.ToString();
                p 
    = new Person();

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

        }

    }

  • 相关阅读:
    账户与安全
    VIM 文档编辑
    ubuntu下搭建Discuz
    数据库管理及增删改查基本操作小结
    poj 3320 jessica's Reading PJroblem 尺取法 -map和set的使用
    poj 3579 Median 二分套二分 或 二分加尺取
    poj 3685 Matrix 二分套二分 经典题型
    POJ 3061  Subsequence   尺取法   挑战146页
    poj 2976 Dropping tests 二分搜索+精度处理
    Codeforces Round #325 (Div. 2) A. Alena's Schedule 暴力枚举 字符串
  • 原文地址:https://www.cnblogs.com/jehnjehn/p/2603663.html
Copyright © 2011-2022 走看看