目錄
泛型與逆變、協變、不變
1. 陣列是協變的
2. 未使用萬用字元的泛型類是不變的(為何泛型類無法強轉)
3. 使用萬用字元的泛型類可逆變可協變(泛型類強轉解決方案)
假設有parent、son、grandson三個類
class parent{}
class son extends parent{}
class grandson extends son{}
由於son可以向上轉型為parent , 所以son 可以向上轉型成parent ,形如這種a>b,則f(a) > f(b),就叫協變,我們都變了,但是關係不會變
會發現編譯器並不會報錯
由於 parent parent = (parent)new son();
所以 parent arr = (parent) new son[5];
雖然一旦執行起來,arr[2] = new parent() 會丟擲arraystoreexception異常
但以下三個在編譯期間均不會報錯
arr[0] = new grandson();
arr[1] = new son();
arr[2] = new parent();
由於son可以向上轉型為parent,但是listparents = (list)new arraylist直接編譯期報錯,同時listsons = (list)new arraylist同樣直接編譯期報錯,這種a>b,但f(a)和f(b)之間完全沒有任何關係,就叫不變
parent obj = (parent)new son();
但以下兩個編譯期直接報錯
listparents = (list)new arraylist();
listsons = (list)new arraylist();
所以泛型類無法強轉
由於son可以向上轉型為parent,且 list extends parent> list = (list extends parent>)new arraylist() ,符合a>b,則f(a) > f(b),所以萬用字元泛型可以是協變的。
但是所有add操作都會報錯,因為? extends parent表示泛型可以是parent的任何子類,乙個父類可以有無限個子類,所以list無法確定究竟該接收哪個,所以選擇全報錯。
parent obj = (parent)new son();
發現這樣寫並不報錯
list extends parent> list = (list extends parent>)new arraylist();
但是所有新增行為都報錯
list.add(new son());
list.add(new grandson());
list.add(new parent());
list> list = new arraylist<>();
同樣所有新增行為都報錯
list.add(new son());
list.add(new grandson());
list.add(new parent());
由於son可以向上轉型為parent,且list super son> superlist = (list super son>)new arraylist(),符合a>b,則f(b) > f(a),所以萬用字元泛型可以是逆變的。只要add(son以及son的子類)就不會報錯,因為乙個類只有有限的父類,可以清晰的知道可以傳入哪些子類,所以不會報錯。
list super son> superlist =(list super son>) new arraylist();
superlist.add(new parent()); // 編譯報錯
superlist.add(new son()); // 不報錯
superlist.add(new grandson()); // 不報錯
所以
1. 如果想要強轉,需要通過萬用字元
2. 如果強轉的過程中,需要對傳入泛型物件進行修改,需要遵循psce原則(有類似add、set等操作,需要使用list super son>;有類似於get的操作,使用list)
public static void main(string args)
private static listforcecast(list> list)
psce原則:
1. 生產者,即set或add,需要用super
2. 消費者,即get,需要用extend
3. 該方法表明,從son或son子類列表中取,加到parent列表中
private static void transfer(list super son> dest, list extend son> from)
泛型協變和逆變3
原文 01.協變性指的是 泛型型別引數可以從乙個派生類隱式轉化為基類 子類可以隱式的轉換為父類 例如string 可以轉化為object 在c 4.0中引入out關鍵字來標記泛型引數支援協變性 list.addrange ienumerable 方法 將其元素新增到 list的末尾的集合。集合自身不...
C 泛型的協變和逆變
可變性是以一種型別安全的方式,將乙個物件當做另乙個物件來使用。如果不能將乙個型別替換為另乙個型別,那麼這個型別就稱之為 不變數。協變和逆變是兩個相互對立的概念 在c 4.0之前,所有的泛型型別都是不變數 即不支援將乙個泛型型別替換為另乙個泛型型別,即使它們之間擁有繼承關係,簡而言之,在c 4.0之前...
協變與逆變
目錄 1.協變 2.逆變 在泛型之前,我們都知道可以將乙個派生類物件賦值給基類變數,這叫做賦值相容性。看下面這個例子 相容性示意圖如上。但是當我們新增泛型機制時 class animal class dog animal delegate t factory class program static...