C# 基礎系列–泛型(抗變和協變)

來源:互聯網
上載者:User

  泛型的抗變和協變是在.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);    }}

  

 這篇寫的不是很好,因為我自己也不是吃的很透,今天在朋友的稍稍點撥下,算是有點 理解這個了。第一次接觸這個東西到現在又一年多了,今天才理解點,慚愧慚愧。

  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.