溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何實(shí)現(xiàn)直接調(diào)用vs反射調(diào)用的實(shí)例教程

發(fā)布時間:2020-07-09 14:10:32 來源:億速云 閱讀:175 作者:Leah 欄目:編程語言

如何實(shí)現(xiàn)直接調(diào)用vs反射調(diào)用的實(shí)例教程?相信很多沒有經(jīng)驗(yàn)的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

直接調(diào)用vs反射調(diào)用

下面就來寫個demo來驗(yàn)證下直接調(diào)用和反射調(diào)用的性能差異,代碼如下:

 1 namespace ConsoleApplication7 2 { 3     class Program 4     { 5         static void Main(string[] args) 6         { 7             //比較直接調(diào)用和反射調(diào)用的性能差異 8             //7ms vs 365ms 9             int times = 1000000;10             var program = new Program();11             CodeTimerHelper.Initialize();12 13             CodeTimerHelper.Time("直接調(diào)用", times, () =>14             {15                 program.Call();16             });17 18             var t = typeof(Program);19             var obj = Activator.CreateInstance(t);20             CodeTimerHelper.Time("反射調(diào)用", 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 }

測試結(jié)果:

如何實(shí)現(xiàn)直接調(diào)用vs反射調(diào)用的實(shí)例教程

從100萬次調(diào)用結(jié)果來看,確實(shí)就像很多人所說的,兩者在性能上具有數(shù)量級的差距。

為什么反射有性能損失

既然反射性能有損失,那具體損失在哪里呢?

1,反射是基于程序集和元數(shù)據(jù)的,在使用反射的時候,會搜索元數(shù)據(jù),而元數(shù)據(jù)是基于字符串的,并且無法預(yù)編譯,所以這一系列的操作對性能有影響。

2,大量的裝箱拆箱也對性能有影響。由于我們對目標(biāo)類型是未知的,而且向方法傳遞的參數(shù)通常是object類型的,所以會有大量的裝箱和拆箱。

反射性能優(yōu)化方案

我們已經(jīng)知道使用反射有性能問題,但是有些場景下又不得不使用反射技術(shù),所以要想辦法優(yōu)化反射性能。

這里就引用老趙公開的System.Linq.Expressions.Expression<TDelegate>表達(dá)式樹的類,與直接調(diào)用進(jìn)行對比,代碼如下:

1 //3,基于表達(dá)式樹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 });

測試結(jié)果:

如何實(shí)現(xiàn)直接調(diào)用vs反射調(diào)用的實(shí)例教程

哇,同樣的100萬次調(diào)用,使用DynamicMethodExecutor調(diào)用跟直接調(diào)用的性能相差無幾。

附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     }

除了使用linq的表達(dá)式樹生成Delegate的方法外,還有比如,CodeDom生成代碼并動態(tài)編譯,或者使用Emit來直接編寫IL的方法來提高反射的性能,但是相對來說,上面這個方法是最簡單的。

至此,整個反射的總結(jié)就完成了!

參考文章

方法的直接調(diào)用,反射調(diào)用與……Lambda表達(dá)式調(diào)用

C#基礎(chǔ)知識梳理系列十五:反射

二、什么是反射、反射可以做些什么

看完上述內(nèi)容,你們掌握如何實(shí)現(xiàn)直接調(diào)用vs反射調(diào)用的實(shí)例教程的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI