C 學習 6 泛型介面中的協變和抗變

2021-10-03 16:13:49 字數 2598 閱讀 9095

1.變體的由來

眾所周知,多型性允許把派生類的物件放在基類的變數中,例如:

cow mycow =

newcow

("犛牛");

animal myanimal = mycow;

之所以cow的型別放在aniaml型別的變數中可行,是因為cow派生自animal。但是,在介面中,這種情況是不適用的,會報錯。例如下面的**:

inte***ce

igetobject

public

class

myclass

:igetobject

<

string

>

}static

void

main

(string

args)

由於myclass支援igetobject介面,則主函式第一行**沒有問題。但是,第二行**預先假定兩個介面型別之間有某種關係,即igetobject型別能夠隱式轉換為igetobject型別,實際上這種關係不存在,所以無法進行相應的隱式型別轉換,程式會報錯,因為我們知道泛型型別的所有型別引數都是不變的。那麼怎麼解決這個問題呢?對,就是通過變體型別。

如果將igetobject介面型別的引數t定義為協變型別,igetobject與igetobject型別之間就可以建立繼承關係,則一種型別的變數就可以包含另外一種型別的值,這與多型性有點類似,但比之更為複雜。

抗變與協變是類似的,但方向相反。抗變不能像協變那樣,把泛型介面值放在使用基型別的變數中,但可以把介面放在使用派生類的介面變數中。

2.協變

要把泛型引數定義為協變,需要在型別定義中使用out關鍵字。對於介面定義,協變型別引數只能用作方法的返回值或屬性get訪問器。如下例子:

inte***ce

igetobject

<

out t>

public

class

myclass

:igetobject

<

string

>

}

在主函式中呼叫:

igetobject<

string

> myclassstr =

newmyclass()

;igetobject<

object

> myclassobj = myclassstr;

string msg =

"武漢加油!"

;string str =

(myclassobj.

dosomething

(msg)).

tostring()

;console.

writeline

(str)

;

結果如下:

武漢加油!
可以看出:編譯器將string dosomething(object value) 轉換為 object dosomething(object value),即實現了igetobject到igetobject 的型別轉換,子——>父的轉換。

3.抗變

要把泛型引數定義為抗變,需要在型別定義中使用in關鍵字。對於介面定義,抗變型別引數只能用作方法引數,不能用作返回型別。如下例子:

//作輸入引數

inte***ce

imyinte***ce

<

in t>

public

class

myclass

:imyinte***ce

<

object

>

}

在主函式中呼叫:

imyinte***ce<

object

> myclass1obj =

newmyclass1()

;imyinte***ce<

string

> myclass2str = myclass1obj;

list<

string

> list =

newlist

<

string

>()

;myclass2str.

dosomething

(list)

;

結果如下:

system.collections.generic.list`1

[system.string

]

可以看出:編譯器將void dosomething(object value) 轉換為 void dosomething(string value) ,即實現了imyinte***ce到imyinte***ce的型別轉換,父——>子的轉換。

3.net framework中的協變與抗變

佔坑,有時間再整理。

4.參考資料

C 泛型 協變和抗變

例如,可以給乙個需要 shape 引數的方法傳送 rectangle 引數嗎?下面用示例說明這些擴充套件的優點。在.net中,引數型別是協變的。假定有 shape 和 rectangle 類,rectangle派生自 shape基類。宣告 display 方法是為了接受 shape 型別的物件作為其...

c 協變和抗變 C 中協變與抗變(逆變)

泛型在.net 2.0中正式的引入。在使用泛型的過程中,聯絡上物件導向的繼承性。往往很容易想當然敲出類似以下 list animallst new list 顯然這樣編譯是不通過的。雖然dog和animal之間有繼承性,但是list和list這兩個類之間並沒有繼承性。如果要解決這樣的問題,用上協變與...

C 中的協變和抗變

net4通過協變和抗變為泛型介面和泛型委託新增了乙個重要擴充套件。協變和抗變指對引數和返回值的型別進行轉換。在.net中,引數型別是協變的。假定有 shape和 rectangle 類,rectangle 派生自shape基類。宣告display 方法是為了接受 shape型別的物件作為其引數 pu...