今天來結束第九章,聊下我們經常忽略,但是編譯器會幫我們完成的"類型判斷和重載決策",理解編譯器如何幫我們完成,相信在寫代碼時會更明確,避免一些編譯出錯,排查的問題,讓我們開發更給力。
我們知道隱式類型的數組以及將方法組轉換為委托類型都需要類型推斷,但將方法組作為其它方法的參數進行轉換時,會顯得極其復雜,我們由淺入深,一步一步來看,編譯器是如何幫我們做的一些推斷。
1 //定義一個泛型方法,參數分別為TInput類型和一個Func<TInput, TResult>類型的委托
2 public static TResult Get<TInput, TResult>(TInput input, Func<TInput, TResult> func)
3 {
4 return func(input);
5 }
6 static void Main(string[] args)
7 {
8 var a = Get("111", x => int.Parse(x));
9 //第一個參數是字符串,所以可以推斷TInput類型有到string類型的隱式轉換
10 //則方法簽名為:public static TResult Get<string, TResult>(string input, Func<string, TResult> func)
11 //第二個參數是一個Lambda表達式,根據返回的類型是一個int,所以可以推斷TResult類型有到int類型的隱式轉換
12 //則方法簽名為:public static int Get<string, int>(string input, Func<string, int> func)
13 //根據上述的步驟,我們推斷出了TInput和TResult類型
14 }
返回類型集合
從上述代碼中,可以看到TResult類型是由Lambda表達式的返回值類型來推斷的,那如果我有多個返回類型又是一種什麼情況呢?請看下面的代碼。
1 var b = Get(1111, delegate (int x) {
2 if (x == 1111)
3 {
4 return "1111";
5 }
6 else
7 {
8 return new object();
9 }
10 });
11 //由上可以推斷出TInput類型有到int類型的隱式轉換,則TInput為int
12 //而返回類型有兩個,一個是string類型,一個是object類型,但是string類型有到object類型的隱式轉換,則TResult為object類型
13 //編譯器幫我們把所有的返回類型放入一個集合,對集合中的類型進行判斷,判斷是否有一個類型是可由剩余其它類型隱式轉換可得,則把這個類型作為返回值的類型
如何選擇正確的重載
如果重載具有二義性,那編譯肯定是過不了的,要麼強制轉換某個參數以符合某個方法的簽名,或者修改重載方法。從參數或者返回類型考慮,請參照下面一條:
從任何類型"轉換成它本身"被認為好於"轉換成其它類型",如
1 static void Debug0(int x) { }
2 static void Debug0(double x) { }
3
4 Debug0(5); //static void Debug0(int x)
5 Debug0(5.0); //static void Debug0(double x)
6 //int有到double的隱式轉換,所以存在二義性,但根據int=>int是好於int=>double的,所以選擇使用static void Debug0(int x)
同理於返回類型,作用於委托或者Lambda表達式,如
1 static int Debug1(Func<int> func) {
2 return func();
3 }
4
5 static double Debug1(Func<double> func)
6 {
7 return func();
8 }
9
10 Debug1(() => 1.1);
11 Debug1(delegate () { return 1.1; });
12 //根據Lambda表達式和匿名方法,Debug1(() => 1.1)和Debug1(delegate () { return 1.1; })返回的類型是double類型,則Lambda表達式和匿名方法轉換成Func<double>類型的實例,調用的則是static double Debug1(Func<double> func)
13 Debug1(() => 1);
14 Debug1(delegate () { return 1; });
15 //根據Lambda表達式和匿名方法,Debug1(() => 1)和Debug1(delegate () { return 1; })返回的類型是int類型,則Lambda表達式和匿名方法轉換成Func<int>類型的實例,調用的則是static double Debug1(Func<int> func)
請斧正。