使用传统的.net反射机制,调用类的方法时,在调用频率大的情况下,会感觉速度很慢。最近浏览
卢彦
的博客时,找到一个他改进后的反射调用类。试用以后感觉效率明显提高,特推荐给大家。作者重新实现了,反射调用方法,但是调用接口和.net原有方法一致。而且调用时抛出的异常为所调用类的实际异常,不像传统方式返回为包装异常。
文章来源: http://www.codeproject.com/csharp/FastMethodInvoker.asp
快速反射调用类
效果测试程序
文章来源: 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
{
classFastInvoke
{
publicdelegateobjectFastInvokeHandler(objecttarget,object[]paramters);
staticobjectInvokeMethod(FastInvokeHandlerinvoke,objecttarget,paramsobject[]paramters)
{
returninvoke(null,paramters);
}
publicstaticFastInvokeHandlerGetMethodInvoker(MethodInfomethodInfo)
{
DynamicMethoddynamicMethod=newDynamicMethod(string.Empty,typeof(object),newType[]{typeof(object),typeof(object[])},methodInfo.DeclaringType.Module);
ILGeneratoril=dynamicMethod.GetILGenerator();
ParameterInfo[]ps=methodInfo.GetParameters();
Type[]paramTypes=newType[ps.Length];
for(inti=0;i<paramTypes.Length;i++)
{
if(ps[i].ParameterType.IsByRef)
paramTypes[i]=ps[i].ParameterType.GetElementType();
else
paramTypes[i]=ps[i].ParameterType;
}
LocalBuilder[]locals=newLocalBuilder[paramTypes.Length];
for(inti=0;i<paramTypes.Length;i++)
{
locals[i]=il.DeclareLocal(paramTypes[i],true);
}
for(inti=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(inti=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(inti=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);
FastInvokeHandlerinvoder=(FastInvokeHandler)dynamicMethod.CreateDelegate(typeof(FastInvokeHandler));
returninvoder;
}
privatestaticvoidEmitCastToReference(ILGeneratoril,System.Typetype)
{
if(type.IsValueType)
{
il.Emit(OpCodes.Unbox_Any,type);
}
else
{
il.Emit(OpCodes.Castclass,type);
}
}
privatestaticvoidEmitBoxIfNeeded(ILGeneratoril,System.Typetype)
{
if(type.IsValueType)
{
il.Emit(OpCodes.Box,type);
}
}
privatestaticvoidEmitFastInt(ILGeneratoril,intvalue)
{
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.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
namespace FastMethodInvoker
{
classFastInvoke
{
publicdelegateobjectFastInvokeHandler(objecttarget,object[]paramters);
staticobjectInvokeMethod(FastInvokeHandlerinvoke,objecttarget,paramsobject[]paramters)
{
returninvoke(null,paramters);
}
publicstaticFastInvokeHandlerGetMethodInvoker(MethodInfomethodInfo)
{
DynamicMethoddynamicMethod=newDynamicMethod(string.Empty,typeof(object),newType[]{typeof(object),typeof(object[])},methodInfo.DeclaringType.Module);
ILGeneratoril=dynamicMethod.GetILGenerator();
ParameterInfo[]ps=methodInfo.GetParameters();
Type[]paramTypes=newType[ps.Length];
for(inti=0;i<paramTypes.Length;i++)
{
if(ps[i].ParameterType.IsByRef)
paramTypes[i]=ps[i].ParameterType.GetElementType();
else
paramTypes[i]=ps[i].ParameterType;
}
LocalBuilder[]locals=newLocalBuilder[paramTypes.Length];
for(inti=0;i<paramTypes.Length;i++)
{
locals[i]=il.DeclareLocal(paramTypes[i],true);
}
for(inti=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(inti=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(inti=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);
FastInvokeHandlerinvoder=(FastInvokeHandler)dynamicMethod.CreateDelegate(typeof(FastInvokeHandler));
returninvoder;
}
privatestaticvoidEmitCastToReference(ILGeneratoril,System.Typetype)
{
if(type.IsValueType)
{
il.Emit(OpCodes.Unbox_Any,type);
}
else
{
il.Emit(OpCodes.Castclass,type);
}
}
privatestaticvoidEmitBoxIfNeeded(ILGeneratoril,System.Typetype)
{
if(type.IsValueType)
{
il.Emit(OpCodes.Box,type);
}
}
privatestaticvoidEmitFastInt(ILGeneratoril,intvalue)
{
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
{
classProgram
{
staticvoidMain(string[]args)
{
Typet=typeof(Person);
MethodInfomethodInfo=t.GetMethod("Say");
Personperson=newPerson();
stringword="hello";
Personp=null;
object[]param=newobject[]{word,p,3};
intTestTimes=100000;//测试次数,可自行调节看效果
#region传统方式反射
try
{
Stopwatchwatch=newStopwatch();
watch.Start();
for(inti=0;i<TestTimes;i++)
{
methodInfo.Invoke(person,param);
}
watch.Stop();
Console.WriteLine(TestTimes.ToString()+"timesinvokedbyReflection:"+watch.ElapsedMilliseconds+"ms");
}
catch(System.Exceptionex)
{
Console.WriteLine("传统方式反射直接错误:"+ex.Message);
Console.WriteLine("传统方式反射内部错误:"+ex.InnerException.Message);
}
#endregion
#region快速反射
try
{
Stopwatchwatch1=newStopwatch();
FastInvoke.FastInvokeHandlerfastInvoker=FastInvoke.GetMethodInvoker(methodInfo);
watch1.Start();
for(inti=0;i<TestTimes;i++)
{
fastInvoker(person,param);
}
watch1.Stop();
Console.WriteLine(TestTimes.ToString()+"timesinvokedbyFastInvoke:"+watch1.ElapsedMilliseconds+"ms");
}
catch(System.Exceptionex)
{
Console.WriteLine("快速反射错误:"+ex.Message);
}
#endregion
#region直接调用
try
{
Stopwatchwatch2=newStopwatch();
watch2.Start();
for(inti=0;i<TestTimes;i++)
{
person.Say(refword,outp,3);
}
watch2.Stop();
Console.WriteLine(TestTimes.ToString()+"timesinvokedbyDirectCall:"+watch2.ElapsedMilliseconds+"ms");
}
catch(System.Exceptionex)
{
Console.WriteLine("直接调用错误:"+ex.Message);
}
#endregion
Console.ReadLine();
}
}
publicclassPerson
{
publicvoidSay(refstringword,outPersonp,intavi)
{
word="ttt"+avi.ToString();
p=newPerson();
//thrownewSystem.Exception("出错了哦");
}
}
}
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace FastMethodInvoker
{
classProgram
{
staticvoidMain(string[]args)
{
Typet=typeof(Person);
MethodInfomethodInfo=t.GetMethod("Say");
Personperson=newPerson();
stringword="hello";
Personp=null;
object[]param=newobject[]{word,p,3};
intTestTimes=100000;//测试次数,可自行调节看效果
#region传统方式反射
try
{
Stopwatchwatch=newStopwatch();
watch.Start();
for(inti=0;i<TestTimes;i++)
{
methodInfo.Invoke(person,param);
}
watch.Stop();
Console.WriteLine(TestTimes.ToString()+"timesinvokedbyReflection:"+watch.ElapsedMilliseconds+"ms");
}
catch(System.Exceptionex)
{
Console.WriteLine("传统方式反射直接错误:"+ex.Message);
Console.WriteLine("传统方式反射内部错误:"+ex.InnerException.Message);
}
#endregion
#region快速反射
try
{
Stopwatchwatch1=newStopwatch();
FastInvoke.FastInvokeHandlerfastInvoker=FastInvoke.GetMethodInvoker(methodInfo);
watch1.Start();
for(inti=0;i<TestTimes;i++)
{
fastInvoker(person,param);
}
watch1.Stop();
Console.WriteLine(TestTimes.ToString()+"timesinvokedbyFastInvoke:"+watch1.ElapsedMilliseconds+"ms");
}
catch(System.Exceptionex)
{
Console.WriteLine("快速反射错误:"+ex.Message);
}
#endregion
#region直接调用
try
{
Stopwatchwatch2=newStopwatch();
watch2.Start();
for(inti=0;i<TestTimes;i++)
{
person.Say(refword,outp,3);
}
watch2.Stop();
Console.WriteLine(TestTimes.ToString()+"timesinvokedbyDirectCall:"+watch2.ElapsedMilliseconds+"ms");
}
catch(System.Exceptionex)
{
Console.WriteLine("直接调用错误:"+ex.Message);
}
#endregion
Console.ReadLine();
}
}
publicclassPerson
{
publicvoidSay(refstringword,outPersonp,intavi)
{
word="ttt"+avi.ToString();
p=newPerson();
//thrownewSystem.Exception("出错了哦");
}
}
}