前言
在.NET 4之前,泛型介面是不變的。.NET 4通過協變和抗變為泛型介面和泛型委託新增了一個重要的擴充套件。協變和抗變指對引數和返回值的型別進行轉換。
我們來看下到底什麼是協變什麼是抗變:
如果某個返回的型別可以由其基類替換,那麼這個型別就是支援協變的
如果某個引數型別可以由其派生類替換,那麼這個型別就是支援逆變(抗變)的。
函式的型別轉換
在理解協變與抗變之前,我們看下面這個例子:
class Program { public static string Tmain(object o) { return "aaa"; } static void Main(string[] args) { string a = "aaa"; object b = Tmain(a); } }
我們仔細看下這個傳值和返回。注意其中發現了兩次隱式轉換。
1、向函式傳值的時候 引數a從string型別轉換成object型別
2、最後接收返回值的時候b由string型別轉換成object型別
我們在返回函式來看。
1、 String Tmain(object o) 可以轉換成string Tmain(string o)
2、 String Tmain(string o) 可以轉換成 object Tmain(string o)
在這裡,也就是說函式輸入的時候輸入型別可以從object轉換成string。基類-派生類
在函式輸出時,函式的輸出型別(返回型別)從string轉換成object。派生類-基類。
這裡就比較接近泛型介面的協變和抗變的概念了。我們再看我們開頭的概念
如果某個返回的型別可以由其基類替換,那麼這個型別就是支援協變的
如果某個引數型別可以由其派生類替換,那麼這個型別就是支援逆變(抗變)的。
理解泛型介面的協變和抗變(in、out)
我們下面來看看泛型介面的協變及抗變的例子:
首先我們看下協變,在C#高階程式設計(第十一版)中指出,如果泛型型別用out關鍵字標註,泛型介面就是協變的。這也就意味著返回型別只能是T。
/// <summary> /// 標識out,意味著返回型別只能是T /// </summary> /// <typeparam name="T"></typeparam> interface Itest<out T> { T Tmain(object value); } public class Test : Itest<string> { public string Tmain(object value) { return value.ToString(); } }
我們呼叫時:
static void Main(string[] args) { Itest<string> itest = new Test(); Itest<object> itestObj = itest; }
在這裡,我們最後接收其返回值的時候,理應由string型別進行接收的,但是這裡我們可以修改,由其基類object型別進行替換。也就是在某個返回型別可以由其基類替換的時候,也就是支援協變了。注意其關鍵點。返回型別、由基類替換派生類。
然後我們再看看那抗變也可稱為逆變。在C#高階程式設計中指出的概念:如果泛型型別用in關鍵字標註,泛型介面就是抗變的。這樣,介面只能把泛型型別T用作其方法的輸入。
/// <summary> /// 標識in,意味著輸入型別只能是T /// </summary> /// <typeparam name="T"></typeparam> interface Itest<in T> { string Tmain(T value); } public class Test : Itest<object> { public string Tmain(object value) { return value.ToString(); } } class Program { static void Main(string[] args) { Itest<object> itest = new Test(); Itest<string> itestStr= itest; } }
這裡我們看上面這個例子,其中返回型別已經是固定的string型別了。而泛型介面中的泛型型別用來作為引數傳遞了。我們再看呼叫時,正常傳入object型別的引數,,但是我們修改傳入引數型別為string型別也是可以的。也就是我們在參入引數時,引數可以由其派生類替換的話,那麼這個類也就是支援抗變(逆變)的。注意其中關鍵點。傳入引數,派生類替換基類。
總結
其實在上述例子及其概念中,我們可以發現,泛型介面的協變及抗變,也就是將型別引數返回或者傳入的情況,在這情況下進行其型別的隱式轉換所遵循的規律。
協變:(使用關鍵字out)返回型別可以由其基類所替代的時候,就是支援協變的。
抗變(逆變):(使用關鍵字in)傳入引數型別可以由其派生類所代替的時候,就是支援抗變(逆變)的。
夫學須靜也,才須學也,非學無以廣才,非志無以成學-------諸葛亮
歡迎大家掃描下方二維碼,和我一起學習更多的C#知識