下面通过编写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万次调用结果如下:

反射调用性能比较_assembly
 

所以得出以下结论:

1. 不用反射,直接调用,效率最高。

2. 实例化反射,效率次之。

3. 快速反射,效率次之。

4. 传统反射,效率最差。

以上调用方式,后3种调用方式虽然效率有先后,但性能在一个数量级上,与传统反射相比,优越性较明显。

另外补充一点,实例化反射如果算上创建实例的性能损耗,试验结果如下图:

反射调用性能比较_i++_02
 

所以,如果需要频繁创建实例,建议不要采用实例化反射。