在.NET 4以前,泛型接口是不變的。.NET 4經過協變和抗變爲泛型接口和泛型委託添加了一個重要的擴展。協變和抗變指對參數和返回值的類型進行轉換。html
咱們來看下到底什麼是協變什麼是抗變:
若是某個返回的類型能夠由其基類替換,那麼這個類型就是支持協變的
若是某個參數類型能夠由其派生類替換,那麼這個類型就是支持逆變(抗變)的。編程
在理解協變與抗變以前,咱們看下面這個例子:c#
class Program { public static string Tmain(object o) { return "aaa"; } static void Main(string[] args) { string a = "aaa"; object b = Tmain(a); } }
咱們仔細看下這個傳值和返回。注意其中發現了兩次隱式轉換。函數
一、向函數傳值的時候 參數a從string類型轉換成object類型學習
二、最後接收返回值的時候b由string類型轉換成object類型spa
咱們在返回函數來看。code
一、 String Tmain(object o) 能夠轉換成string Tmain(string o)htm
二、 String Tmain(string o) 能夠轉換成 object Tmain(string o)blog
在這裏,也就是說函數輸入的時候輸入類型能夠從object轉換成string。基類-派生類接口
在函數輸出時,函數的輸出類型(返回類型)從string轉換成object。派生類-基類。
這裏就比較接近泛型接口的協變和抗變的概念了。咱們再看咱們開頭的概念
若是某個返回的類型能夠由其基類替換,那麼這個類型就是支持協變的
若是某個參數類型能夠由其派生類替換,那麼這個類型就是支持逆變(抗變)的。
咱們下面來看看泛型接口的協變及抗變的例子:
首先咱們看下協變,在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#知識