泛型接口的抗變和協變

1, 泛型接口的協變測試

  若是泛型類型用out關鍵字標註,泛型接口就是協變的。這也意味着返回類型只能是T。spa

    泛型接口的抗變code

      若是泛型類型用in關鍵字標註,泛型接口就是抗變的。這樣,接口只能把泛型類型T用做其方法的輸入,即方法的參數。對象

這是泛型接口的抗變和協變的定義,那咱們下面來用代碼說明,直接上代碼,blog

 1     /// <summary>
 2     /// 泛型接口
 3     /// </summary>
 4     /// <typeparam name="T"></typeparam>
 5     public interface IDisplay< T >
 6     {
 7         void Show(T item);
 8     }
 9 
10     /// <summary>
11     /// 實現泛型接口IDisaplay
12     /// </summary>
13     /// <typeparam name="T"></typeparam>
14     public class ShapDisplay<T> : IDisplay<T>
15     {
16         public void Show(T item)
17         {
18             Console.WriteLine("測試成功!");
19         }
20     }
21 
22     /// <summary>
23     /// 父類
24     /// </summary>
25     public class ParentClass
26     {
27     }
28 
29     /// <summary>
30     /// 子類
31     /// </summary>
32     public class SubClass : ParentClass
33     {
34     }

 

2, 上面定義了接口和實現了接口,接下來咱們來測試實現了接口的類,上代碼接口

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             // 用子類實例化泛型類(簡稱子類對象)
 6             IDisplay<SubClass> sub1 = new ShapDisplay<SubClass>();
 7 
 8             // 用父類實例化泛型類(簡稱父類對象)
 9             IDisplay<ParentClass> par1 = new ShapDisplay<ParentClass>();
10 
11             // 用父類類型接收子類對象(子類對象→父類類型)協變
12             IDisplay<ParentClass> parent = sub1;
13 
14             // 用子類類型接收父類對象(父類對象→子類類型)抗變
15             IDisplay<SubClass> sub = par1;
16 
17             Console.ReadKey();
18 
19         }
20     }

咱們會發現代碼行12和15會報錯,編譯不過,爲何呢?string

緣由很簡單,由於咱們在最上面是這樣定義接口的時候,沒有加out也沒有加in,即泛型接口默認不會支持抗變和協變,因此編譯會報錯。it

好,那咱們接下來給泛型接口修改一下,以下代碼編譯

1 /// <summary>
2     /// 泛型接口
3     /// </summary>
4     /// <typeparam name="T"></typeparam>
5     public interface IDisplay<out T>
6     {
7         void Show(T item);
8     }

泛型前面加上out以後,會發現接口中的Show會報錯,這又是爲什麼呢?class

根據泛型接口的協變,若是泛型類型用out關鍵字標註,這意味着返回類型只能是T。也就是說方法的返回類型應該是T,而咱們Show方法中,方法的參數是T,因此不符合規定,報錯。

那咱們再來修改代碼,以下

1     /// <summary>
2     /// 泛型接口
3     /// </summary>
4     /// <typeparam name="T"></typeparam>
5     public interface IDisplay<in T>
6     {
7         void Show(T item);
8     }

接口徹底沒問題,可是,囧,main方法中12行依然報錯,wtf?

由於泛型類型是用in來標註的,這表示該泛型只支持抗變,12行代碼是協變,因此會報錯。

到此,泛型接口的抗變和協變也就解釋完畢,總結以下3點,

①泛型接口,若是泛型類型前沒有關鍵字out或者in來標註,則該泛型接口不支持抗變和協變,即只能是什麼對象指向什麼類型。

②若是泛型接口,泛型類型前有關鍵字out標註,則表示其方法的輸出爲T類型,也就是方法的返回值。同時該泛型接口支持協變,即,能夠用父類的類型指向子類的對象。

③若是泛型接口,泛型類型前面有關鍵字in標註,則表示其方法的輸入爲T類型,也就是方法的參數。該泛型接口支持抗變,也就是能夠用子類的類型指向父類的對象。

相關文章
相關標籤/搜索