下面通过编写Demo的方式,验证各种反射的性能。
1、传统方式反射
01.
Type t = typeof(Person);
02.
MethodInfo methodInfo = t.GetMethod("Say");
03.
Person person = new Person();
04.
string word = "hello";
05.
Person p = null;
06.
object[] param = new object[] { word, p, 3 };
07.
int TestTimes = 1000000; //测试次数,可自行调节看效果
08.
09.
#region 传统方式反射
10.
try
11.
{
12.
Stopwatch watch = new Stopwatch();
13.
watch.Start();
14.
for (int i = 0; i < TestTimes; i++)
15.
{
16.
methodInfo.Invoke(person, param);
17.
}
18.
watch.Stop();
19.
Console.WriteLine(TestTimes.ToString() + " times invoked by Reflection: " + watch.ElapsedMilliseconds + "ms");
20.
}
21.
catch (System.Exception ex)
22.
{
23.
Console.WriteLine("传统方式反射 直接错误:" + ex.Message);
24.
Console.WriteLine("传统方式反射 内部错误:" + ex.InnerException.Message);
25.
}
26.
#endregion
2、实例化反射
01.
#region 实例化反射
02.
try
03.
{
04.
//Stopwatch watch = new Stopwatch();
05.
//watch.Start();
06.
//for (int i = 0; i < TestTimes; i++)
07.
//{
08.
// Assembly Asm = Assembly.Load("testInvoke");//反射出空间
09.
// Type type = Asm.GetType("testInvoke.Person");//反射出空间下的类
10.
// object AssClas = Activator.CreateInstance(type);//动态实例化反射回来的指定空间下的指定类
11.
// IPerson objPerson = (Person)AssClas; ////转换为接口类型
12.
// objPerson.Say(ref word, out p, 3);
13.
//}
14.
//watch.Stop();
15.
//Console.WriteLine(TestTimes.ToString() + " times invoked by InstanceReflection@1: " + watch.ElapsedMilliseconds + "ms");
16.
17.
Assembly Asm = Assembly.Load("testInvoke");//反射出空间
18.
Type type = Asm.GetType("testInvoke.Person");//反射出空间下的类
19.
object AssClas = Activator.CreateInstance(type);//动态实例化反射回来的指定空间下的指定类
20.
IPerson objPerson = (Person)AssClas; //转换为接口类型
21.
Stopwatch watch = new Stopwatch();
22.
watch.Start();
23.
for (int i = 0; i < TestTimes; i++)
24.
{
25.
objPerson.Say(ref word, out p, 3);
26.
}
27.
watch.Stop();
28.
Console.WriteLine(TestTimes.ToString() + " times invoked by InstanceReflection@2: " + watch.ElapsedMilliseconds + "ms");
29.
30.
}
31.
catch (System.Exception ex)
32.
{
33.
Console.WriteLine("实例化反射 错误:" + ex.Message);
34.
}
35.
#endregion
3、快速反射
01.
#region 快速反射
02.
try
03.
{
04.
Stopwatch watch1 = new Stopwatch();
05.
FastInvoke.FastInvokeHandler fastInvoker = FastInvoke.GetMethodInvoker(methodInfo);
06.
watch1.Start();
07.
for (int i = 0; i < TestTimes; i++)
08.
{
09.
fastInvoker(person, param);
10.
}
11.
watch1.Stop();
12.
Console.WriteLine(TestTimes.ToString() + " times invoked by FastInvoke: " + watch1.ElapsedMilliseconds + "ms");
13.
}
14.
catch (System.Exception ex)
15.
{
16.
Console.WriteLine("快速反射 错误:" + ex.Message);
17.
}
18.
#endregion
001.
using System;
002.
using System.Collections.Generic;
003.
using System.Linq;
004.
using System.Text;
005.
using System.Reflection.Emit;
006.
using System.Reflection;
007.
008.
namespace testInvoke
009.
{
010.
class FastInvoke
011.
{
012.
public delegate object FastInvokeHandler(object target, object[] paramters);
013.
014.
static object InvokeMethod(FastInvokeHandler invoke, object target,params object[] paramters)
015.
{
016.
return invoke(null, paramters);
017.
}
018.
019.
public static FastInvokeHandler GetMethodInvoker(MethodInfo methodInfo)
020.
{
021.
DynamicMethod dynamicMethod = new DynamicMethod(string.Empty,typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo.DeclaringType.Module);
022.
ILGenerator il = dynamicMethod.GetILGenerator();
023.
ParameterInfo[] ps = methodInfo.GetParameters();
024.
Type[] paramTypes = new Type[ps.Length];
025.
for (int i = 0; i < paramTypes.Length; i++)
026.
{
027.
if (ps[i].ParameterType.IsByRef)
028.
paramTypes[i] = ps[i].ParameterType.GetElementType();
029.
else
030.
paramTypes[i] = ps[i].ParameterType;
031.
}
032.
LocalBuilder[] locals = new LocalBuilder[paramTypes.Length];
033.
034.
for (int i = 0; i < paramTypes.Length; i++)
035.
{
036.
locals[i] = il.DeclareLocal(paramTypes[i], true);
037.
}
038.
for (int i = 0; i < paramTypes.Length; i++)
039.
{
040.
il.Emit(OpCodes.Ldarg_1);
041.
EmitFastInt(il, i);
042.
il.Emit(OpCodes.Ldelem_Ref);
043.
EmitCastToReference(il, paramTypes[i]);
044.
il.Emit(OpCodes.Stloc, locals[i]);
045.
}
046.
if (!methodInfo.IsStatic)
047.
{
048.
il.Emit(OpCodes.Ldarg_0);
049.
}
050.
for (int i = 0; i < paramTypes.Length; i++)
051.
{
052.
if (ps[i].ParameterType.IsByRef)
053.
il.Emit(OpCodes.Ldloca_S, locals[i]);
054.
else
055.
il.Emit(OpCodes.Ldloc, locals[i]);
056.
}
057.
if (methodInfo.IsStatic)
058.
il.EmitCall(OpCodes.Call, methodInfo, null);
059.
else
060.
il.EmitCall(OpCodes.Callvirt, methodInfo, null);
061.
if (methodInfo.ReturnType == typeof(void))
062.
il.Emit(OpCodes.Ldnull);
063.
else
064.
EmitBoxIfNeeded(il, methodInfo.ReturnType);
065.
066.
for (int i = 0; i < paramTypes.Length; i++)
067.
{
068.
if (ps[i].ParameterType.IsByRef)
069.
{
070.
il.Emit(OpCodes.Ldarg_1);
071.
EmitFastInt(il, i);
072.
il.Emit(OpCodes.Ldloc, locals[i]);
073.
if (locals[i].LocalType.IsValueType)
074.
il.Emit(OpCodes.Box, locals[i].LocalType);
075.
il.Emit(OpCodes.Stelem_Ref);
076.
}
077.
}
078.
079.
il.Emit(OpCodes.Ret);
080.
FastInvokeHandler invoder = (FastInvokeHandler)dynamicMethod.CreateDelegate(typeof(FastInvokeHandler));
081.
return invoder;
082.
}
083.
084.
private static void EmitCastToReference(ILGenerator il, System.Type type)
085.
{
086.
if (type.IsValueType)
087.
{
088.
il.Emit(OpCodes.Unbox_Any, type);
089.
}
090.
else
091.
{
092.
il.Emit(OpCodes.Castclass, type);
093.
}
094.
}
095.
096.
private static void EmitBoxIfNeeded(ILGenerator il, System.Type type)
097.
{
098.
if (type.IsValueType)
099.
{
100.
il.Emit(OpCodes.Box, type);
101.
}
102.
}
103.
104.
private static void EmitFastInt(ILGenerator il, int value)
105.
{
106.
switch (value)
107.
{
108.
case -1:
109.
il.Emit(OpCodes.Ldc_I4_M1);
110.
return;
111.
case 0:
112.
il.Emit(OpCodes.Ldc_I4_0);
113.
return;
114.
case 1:
115.
il.Emit(OpCodes.Ldc_I4_1);
116.
return;
117.
case 2:
118.
il.Emit(OpCodes.Ldc_I4_2);
119.
return;
120.
case 3:
121.
il.Emit(OpCodes.Ldc_I4_3);
122.
return;
123.
case 4:
124.
il.Emit(OpCodes.Ldc_I4_4);
125.
return;
126.
case 5:
127.
il.Emit(OpCodes.Ldc_I4_5);
128.
return;
129.
case 6:
130.
il.Emit(OpCodes.Ldc_I4_6);
131.
return;
132.
case 7:
133.
il.Emit(OpCodes.Ldc_I4_7);
134.
return;
135.
case 8:
136.
il.Emit(OpCodes.Ldc_I4_8);
137.
return;
138.
}
139.
140.
if (value > -129 && value < 128)
141.
{
142.
il.Emit(OpCodes.Ldc_I4_S, (SByte)value);
143.
}
144.
else
145.
{
146.
il.Emit(OpCodes.Ldc_I4, value);
147.
}
148.
}
149.
}
150.
}
4、不用反射,直接调用www.it165.net
01.
#region 直接调用
02.
try
03.
{
04.
Stopwatch watch2 = new Stopwatch();
05.
watch2.Start();
06.
for (int i = 0; i < TestTimes; i++)
07.
{
08.
person.Say(ref word, out p, 3);
09.
}
10.
watch2.Stop();
11.
Console.WriteLine(TestTimes.ToString() + " times invoked by DirectCall: " + watch2.ElapsedMilliseconds + "ms");
12.
}
13.
catch (System.Exception ex)
14.
{
15.
Console.WriteLine("直接调用 错误:" + ex.Message);
16.
}
17.
#endregion
以上4种调用方式,100万次调用结果如下:

所以得出以下结论:
1. 不用反射,直接调用,效率最高。
2. 实例化反射,效率次之。
3. 快速反射,效率次之。
4. 传统反射,效率最差。
以上调用方式,后3种调用方式虽然效率有先后,但性能在一个数量级上,与传统反射相比,优越性较明显。
另外补充一点,实例化反射如果算上创建实例的性能损耗,试验结果如下图:

所以,如果需要频繁创建实例,建议不要采用实例化反射。
本文通过编写Demo验证了四种反射方式在执行百万次调用任务时的性能表现,结果显示直接调用效率最高,实例化反射次之,快速反射再次之,而传统反射效率最低。
184

被折叠的 条评论
为什么被折叠?



