使用傳統的.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("出錯了哦");
????????}
????}
}