C# 泛型接口的抗變和協變。本站提示廣大學習愛好者:(C# 泛型接口的抗變和協變)文章只能為提供參考,不一定能成為您想要的結果。以下是C# 泛型接口的抗變和協變正文
1, 泛型接口的協變
如果泛型類型用out關鍵字標注,泛型接口就是協變的。這也意味著返回類型只能是T。
泛型接口的抗變
如果泛型類型用in關鍵字標注,泛型接口就是抗變的。這樣,接口只能把泛型類型T用作其方法的輸入,即方法的參數。
這是泛型接口的抗變和協變的定義,那我們下面來用代碼說明,直接上代碼,
/// <summary>
/// 泛型接口
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IDisplay< T >
{
void Show(T item);
}
/// <summary>
/// 實現泛型接口IDisaplay
/// </summary>
/// <typeparam name="T"></typeparam>
public class ShapDisplay<T> : IDisplay<T>
{
public void Show(T item)
{
Console.WriteLine("測試成功!");
}
}
/// <summary>
/// 父類
/// </summary>
public class ParentClass
{
}
/// <summary>
/// 子類
/// </summary>
public class SubClass : ParentClass
{
}
2, 上面定義了接口和實現了接口,接下來我們來測試實現了接口的類,上代碼
class Program
{
static void Main(string[] args)
{
// 用子類實例化泛型類(簡稱子類對象)
IDisplay<SubClass> sub1 = new ShapDisplay<SubClass>();
// 用父類實例化泛型類(簡稱父類對象)
IDisplay<ParentClass> par1 = new ShapDisplay<ParentClass>();
// 用父類類型接收子類對象(子類對象→父類類型)協變
IDisplay<ParentClass> parent = sub1;
// 用子類類型接收父類對象(父類對象→子類類型)抗變
IDisplay<SubClass> sub = par1;
Console.ReadKey();
}
}
我們會發現代碼行12和15會報錯,編譯不過,為什麼呢?
原因很簡單,因為我們在最上面是這樣定義接口的時候,沒有加out也沒有加in,即泛型接口默認不會支持抗變和協變,所以編譯會報錯。
好,那我們接下來給泛型接口修改一下,如下代碼
/// <summary>
/// 泛型接口
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IDisplay<out T>
{
void Show(T item);
}
泛型前面加上out之後,會發現接口中的Show會報錯,這又是為何呢?
根據泛型接口的協變,如果泛型類型用out關鍵字標注,這意味著返回類型只能是T。也就是說方法的返回類型應該是T,而我們Show方法中,方法的參數是T,所以不符合規定,報錯。
那我們再來修改代碼,如下
/// <summary>
/// 泛型接口
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IDisplay<in T>
{
void Show(T item);
}
接口完全沒問題,但是,囧,main方法中12行依然報錯,wtf?
因為泛型類型是用in來標注的,這表示該泛型只支持抗變,12行代碼是協變,所以會報錯。
到此,泛型接口的抗變和協變也就解釋完畢,總結如下3點,
①泛型接口,如果泛型類型前沒有關鍵字out或者in來標注,則該泛型接口不支持抗變和協變,即只能是什麼對象指向什麼類型。
②如果泛型接口,泛型類型前有關鍵字out標注,則表示其方法的輸出為T類型,也就是方法的返回值。同時該泛型接口支持協變,即,可以用父類的類型指向子類的對象。
③如果泛型接口,泛型類型前面有關鍵字in標注,則表示其方法的輸入為T類型,也就是方法的參數。該泛型接口支持抗變,也就是可以用子類的類型指向父類的對象。
以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持!