c in depth 之泛型實參的型別推斷

2022-03-04 14:02:29 字數 1516 閱讀 8083

呼叫泛型方法時,指定型別實參常常會顯得很多餘。為簡化工作,c#2編譯器被賦予了一定的「智慧型」,讓你在呼叫方法時,不需要顯式宣告型別實參。

在深入討論這個主題之前,必須強調一下:型別推斷只適用於泛型方法,不適用於泛型型別。

例子:static listmakelist(t first,t second)

listlist=makelist("line1","line2");

方法中的每個引數都宣告為型別t。即使拿掉方法中呼叫表示式的部分,也很容易看出在呼叫方法時,為t使用的型別實參是string。編譯器允許將其省略,變成:

listlist=makelist("line2","line2");

使用型別推斷並非總是意味著增加了可讀性。某些情況下會造成讀者更難判斷你要使用什麼型別實參-即使編譯器能輕鬆地判斷出來。建議具體情況具體分析。在推斷可用的時候,讓編譯器推斷型別實參,多數情況下都沒有問題。

注意,編譯器之所以能夠確定我們要將string作為型別實參使用,是因為對list的賦值也在起作用,它也指定了並且必須指定型別實參。然而,假如編譯器推斷錯了你想要使用的型別實參,你仍可能得到乙個編譯錯誤。

編譯器為什麼會弄錯呢?假定實際想用object作為型別實參。我們傳遞的方法實參仍是有效的,編譯器認為我們想要的是string,因為傳遞的兩個引數都是字串。修改其中乙個實參,把它顯示轉換為object,型別推斷就會失敗。因為乙個方法實參指出t應該是string,另乙個指出t應該是乙個object。此時,編譯器會考慮這種情況並且告知使用者將t設為object能滿足一切情況,將t設為string則不能。但是,在c#語言規範中,只提供了有限的推斷步驟。其基本步驟如下:

1.針對每乙個方法實參(普通圓括號中的引數,而不是尖括號中的),都嘗試推斷出泛型方法的一些型別實參。這一步是相當簡單的技術

2.驗證步驟一的所有結果都是一致的—換言之,假如從乙個方法實參中推斷出了某型別引數的型別實參,但根據另外乙個型別實參推斷出同乙個型別引數具有另乙個型別實參,則此次方法呼叫的推斷失敗。

3.驗證泛型方法需要的所有型別實參都已被推斷出來,不能讓編譯器推斷一部分,自己顯式指定另一部分。要麼全部推斷,要麼全部指定。

型別推斷可以結合基於型別引數數量的型別名稱過載的想法,來簡化泛型型別的使用。

程式清單:

using

system;

using

system.collections.generic;

using

system.linq;

using

system.text;

using

system.threading.tasks;

namespace

型別推斷

static

void main(string

args)}}

}

執行結果:

試驗知:型別推斷中,如果型別如object,至少要強制轉換型別實參中的乙個引數,否則推斷失敗。

泛型之泛型類

public class a 構造引數型別上使用泛型 public a t t 方法返回值上使用泛型 public t gett 方法的引數上使用泛型 這是泛型類的方法,而不是泛型方法 public void sett t t 方法的返回值和引數型別上使用泛型 public t foo t t pu...

泛型之泛型類

public class a 構造引數型別上使用泛型 public a t t 方法返回值上使用泛型 public t gett 方法的引數上使用泛型 這是泛型類的方法,而不是泛型方法 public void sett t t 方法的返回值和引數型別上使用泛型 public t foo t t pu...

泛型之泛型類

public class a 構造引數型別上使用泛型 public a t t 方法返回值上使用泛型 public t gett 方法的引數上使用泛型 這是泛型類的方法,而不是泛型方法 public void sett t t 方法的返回值和引數型別上使用泛型 public t foo t t pu...