Many people say that using reflection will cause performance problems. How much slower will it be than direct calling? Let’s test it below.
Let’s write a demo to verify the performance difference between direct call and reflective call. The code is as follows:
1 namespace ConsoleApplication7 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //比较直接调用和反射调用的性能差异 8 //7ms vs 365ms 9 int times = 1000000;10 var program = new Program();11 CodeTimerHelper.Initialize();12 13 CodeTimerHelper.Time("直接调用", times, () =>14 {15 program.Call();16 });17 18 var t = typeof(Program);19 var obj = Activator.CreateInstance(t);20 CodeTimerHelper.Time("反射调用", times, () =>21 {22 t.InvokeMember("Call", BindingFlags.InvokeMethod, null, obj, null);23 });24 25 Console.ReadKey();26 }27 28 /// <summary>29 /// 测试方法30 /// </summary>31 public void Call()32 {33 }34 35 }36 }
Test results:
Judging from the results of 1 million calls, it is indeed as many people said, Two There is an order of magnitude difference in performance.
Since there is a loss in reflection performance, where is the specific loss?
1. Reflection is based on assembly and metadata. When using reflection, metadata will be searched. Metadata is based on strings and cannot be precompiled, so this series of operations is Performance is affected.
2, a large number of boxing and unboxing also have an impact on performance. Since we don't know the target type, and the parameters passed to the method are usually of type object, there will be a lot of boxing and unboxing.
We already know that there are performance issues with using reflection, but in some scenarios we have to use reflection technology, so we must find ways to optimize reflection performance.
Here we quote the System.Linq.Expressions.Expression
1 //3,基于表达式树2 var methodInfo = t.GetMethod("Call");3 var executor = new DynamicMethodExecutor(methodInfo);4 CodeTimerHelper.Time("Dynamic executor", times, () =>5 {6 executor.Execute(obj, null);7 });
Test results:
Wow, for the same 1 million calls, the performance of calling using DynamicMethodExecutor is almost the same as that of direct calling.
Attached is the encapsulation code of DynamicMethodExecutor:
1 /// <summary> 2 /// 3 /// </summary> 4 public class DynamicMethodExecutor 5 { 6 private Func<object, object[], object> m_execute; 7 8 public DynamicMethodExecutor(MethodInfo methodInfo) 9 {10 this.m_execute = this.GetExecuteDelegate(methodInfo);11 }12 13 public object Execute(object instance, object[] parameters)14 {15 return this.m_execute(instance, parameters);16 }17 18 private Func<object, object[], object> GetExecuteDelegate(MethodInfo methodInfo)19 {20 // parameters to execute21 ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance");22 ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");23 24 // build parameter list25 List<Expression> parameterExpressions = new List<Expression>();26 ParameterInfo[] paramInfos = methodInfo.GetParameters();27 for (int i = 0; i < paramInfos.Length; i++)28 {29 // (Ti)parameters[i]30 BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));31 UnaryExpression valueCast = Expression.Convert(valueObj, paramInfos[i].ParameterType);32 parameterExpressions.Add(valueCast);33 }34 35 // non-instance for static method, or ((TInstance)instance)36 Expression instanceCast = methodInfo.IsStatic ? null : Expression.Convert(instanceParameter, methodInfo.ReflectedType);37 38 // static invoke or ((TInstance)instance).Method39 MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, parameterExpressions);40 41 // ((TInstance)instance).Method((T0)parameters[0], (T1)parameters[1], ...)42 if (methodCall.Type == typeof(void))43 {44 Expression<Action<object, object[]>> lambda = Expression.Lambda<Action<object, object[]>>(methodCall, instanceParameter, parametersParameter);45 Action<object, object[]> execute = lambda.Compile();46 return (instance, parameters) =>47 {48 execute(instance, parameters);49 return null;50 };51 }52 else53 {54 UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));55 Expression<Func<object, object[], object>> lambda = Expression.Lambda<Func<object, object[], object>>(castMethodCall, instanceParameter, parametersParameter);56 return lambda.Compile();57 }58 }
In addition to using the expression tree of linq to generate Delegate, there are also, for example, CodeDom generation Code and compile it dynamically, or use Emit to write IL directly to improve the performance of reflection, but relatively speaking, the above method is the simplest.
At this point, the summary of the entire reflection is complete!
Direct calling of methods, reflection calling and...Lambda expression calling
C# basic knowledge sorting series fifteen: reflection
2. What is reflection and what reflection can do
The above is the detailed content of Direct call vs reflective call example tutorial. For more information, please follow other related articles on the PHP Chinese website!