泛型的抗變和協變是在.NET4.0中才增加, 這對之前的介面的一個不錯的擴充。抗變和協變是指標對參數和傳回值的類型轉換。
看了下評論,抗變和協變 在 msdn的翻譯是逆變和協變。我先是看C#進階編程第七版的中文版的,所以還是比較習慣抗變和協變。
抗變和協變的在msdn的解釋
在 C# 和 Visual Basic 中,協變和逆變允許數群組類型、委託類型和泛型型別參數進行隱式引用轉換。 協變保留分配相容性,逆變與之相反。
關鍵字的傳送門:out
通過協變,可以使用與泛型參數指定的衍生類別型相比,派生程度更大的類型。 這樣可以對委託類型和實現變體介面的類進行隱式轉換。 參考型別支援協變和逆變,但實值型別不支援。
in
通過逆變,可以使用與泛型參數指定的衍生類別型相比,派生程度更小的類型。 這樣可以對委託類型和實現變體介面的類進行隱式轉換。 參考型別支援泛型型別參數中的協變和逆變,但實值型別不支援。
在.NET中 參數類型是協變,傳回值是抗變。
不要廢話了,先定義兩個我們例子用的實體類---基類 RectangleBase 衍生類別--Rectangle
public class RectangleBase { public int ID { get; set; } } public class Rectangle : RectangleBase { public string Name { get; set; } }
如果有個方法 public void Display(RectangleBase r) 我們傳入一個 Rectangle 的實體,那麼就是一個參數類型的協變
如果有個方法public RectangleBase GetRectangle() 我們這裡 RectangleBase b = GetRectangle() 那麼這就是方法傳回型別的抗變。
在4.0之前,泛型介面是不擁有想上面類的便利性。很幸運,微軟在 4.0對泛型介面擴充這寫!
協變
如果泛型介面中有關鍵字 out的,那個這個泛型介面就是協變。這個就定義了這個介面只能傳回型別只能是T。
我們先定義一個介面
public interface IIndex<out T> { T this[int index] { get; } int Count { get; } }
我們的實作類別:
public class RectangleCollection : IIndex<Rectangle> { List<Rectangle> list = new List<Rectangle>(); public Rectangle this[int index] { get { if (index < 0 || index > Count) throw new ArgumentOutOfRangeException("index"); return list[index]; } } public int Count { get { return list.Count; } } public void Add(Rectangle value) { list.Add(value); } }
然後我們在控制台是這樣:
var list = new RectangleCollection(); list.Add(new Rectangle { ID = 1, Name = "111" }); list.Add(new Rectangle { ID = 2, Name = "222" }); list.Add(new Rectangle { ID = 3, Name = "33" }); IIndex<RectangleBase> Bas = list; for (int i = 0; i < Bas.Count; i++) { Console.WriteLine(Bas[i].ID); } Console.Read();
協變很簡單吧。。。如果你吧關鍵字out 去掉後,編譯器很快就會個告訴你 IIndex<RectangleBase> Bas = list; 錯誤。因為你沒有告訴他 這個T是可以變的
抗變
如果泛型介面有關鍵字in ,那麼表示這個泛型介面是可以抗變的。這樣,介面也只能把泛型型別T用作方法的輸入。
定義泛型抗變的 介面
public interface IDisplay(in T){ void Show(T item);}
抗變類:
public class RectangleDisplay: IDisplay<RectangleBase>{ public void Show(RectangBase item) { Console.WrileLine(item.ID); }}
這篇寫的不是很好,因為我自己也不是吃的很透,今天在朋友的稍稍點撥下,算是有點 理解這個了。第一次接觸這個東西到現在又一年多了,今天才理解點,慚愧慚愧。