方法多載(Method Overloading)與 dynamic

方法多載(Overloading)是指多個名稱相同但參數個數或型別不同的方法,編譯器依傳入參數的個數、型別與順序決定使用哪一個方法。概念上多載讓方法變得更彈性,能接受不同參數組合,符合更多應用情境。舉個常見的例子,Convert.ToByte() 可傳入 int, short, string, float, double, decimal, char… 等輸入值,將其轉成 byte,傳入 string 時還能指定 16 進位(fromBase)或 IFormatProvider。

我有個根深蒂固的觀念-多載解析都發生在編譯期間,編譯器依參數將函式指標指向同名方法的其中一個。上回在談擴充方法參數傳入 dynamic 型別出錯時提到:「當 dynamic 遇上多載介面解析,一律視為 object 就對了」,但事後想想覺得怪,「多載解析都是在編譯期間完成」不適用 dynamic 型別吧?dynamic 要到執行期間才知確實型別,編譯期間要如何判斷該套用哪個多載實作?廢話不多說,做個實驗便知:有個 OverloadingMethod 共有接收 int 或 string 兩個多載版本,測試時第一次傳入數字、第二次傳入字串、第三次將數字轉型成 dynamic。

class Program
{
    static void Main(string[] args)
    {
        OverloadingMethod(12345);
        OverloadingMethod("ABCDEF");
        OverloadingMethod((dynamic)12345);
        Console.Read();
    }
 
    static void OverloadingMethod(int i)
    {
        Console.WriteLine($"int version: {i}");
    }
 
    static void OverloadingMethod(string s)
    {
        Console.WriteLine($"string version: {s}");
    }
 
}

編譯後以 ildasm 解譯回 MSIL,答案揭曉!如下圖所示,前兩次分別呼叫 int 及 string 版多載方法(黃底部分),第三次則又臭又長,透過 System.Runtime.CompilerServices、System.CSharp.RuntimeBinder 命名空間的物件與方法隔水加熱完成。

改用 LINQPad 的 IL 檢視比較簡潔,原則上類似 Reflection,第三次呼叫,方法名稱"OverloadingMethod"變成字串變數,以 Invoke 方式執行。

所以,結論是多載原則上是在編譯期間決定實際呼叫方法沒錯,但遇上 dynamic 只能留到執行期間再決定。最後,以 C# in Depth- Overloading 的這段說明為本議題劃上句點:

At compile time, the compiler works out which one it's going to call, based on the compile time types of the arguments and the target of the method call. (I'm assuming you're not using dynamic here, which complicates things somewhat.)

歡迎推文分享:
Published 03 August 2017 05:54 PM 由 Jeffrey
Filed under:
Views: 3,068



意見

沒有意見

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<August 2017>
SunMonTueWedThuFriSat
303112345
6789101112
13141516171819
20212223242526
272829303112
3456789
 
RSS
創用 CC 授權條款
【廣告】
twMVC

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication