C#中的協變和逆變
前言
這篇文章簡單說說C#中的協變和逆變。
在C#編程中,由於存在類型之間的強制轉換,很容易會出現所謂的類型可變性說法,存在協變、逆變、不變三種。
就比如前一篇文章介紹的泛型概念,如果創建了泛型類型的實例,編譯器會接受泛型類型聲明以及類型參數來創建構造類型。但是在日常使用過程中,我們可能會將派生類型分配給基類型的變數,有時候會出現錯誤。
這裡就存在一個賦值兼容性問題。
每一個變數都有一種類型,可以將派生類對象的實例賦值給基類變數(好比之前子類聲明的變數可以賦值給父類聲明的變數一樣)。
如下所示:
class People
{
public int Age = 27;
}
class AhuiPeople : People
{
}
People ahui = new People();
People people = new AhuiPeople();
Console.WriteLine("Age:"+people.Age);
Console.ReadKey();
協變和逆變
我們按照同樣的邏輯,在泛型委託中進行這種強類型的轉換,會發現即使基類和派生類之間可以進行正常的轉換,但是委託之間不能進行轉換會出現異常錯誤提示。
具體如下程式碼所示:
delegate T AgeDelegate<T>();
static AhuiPeople GetAge()
{
return new AhuiPeople();
}
在轉換過程中,委託的具體用法,但是這樣子編譯器提示錯誤。
AgeDelegate<AhuiPeople> ahui = GetAge;
AgeDelegate<People> people = ahui;
錯誤提示
這就是上面解釋的那樣子,基類和派生類之間可以進行轉換但是委託之間未存在關聯,無法進行強制類型的轉換。
那麼想解決這個問題就引入了協變來解決。
如果派生類只是用於輸出值,那麼這種結構化的委託有效性之間的常數關係叫做協變,可通過主動告知編譯器我們的期望,使用Out關鍵字標記委託聲明中的類型參數。
delegate T AgeDelegate<out T>();
修改成這樣子後,上面錯誤演示的程式碼編譯器就可以正常編譯通過了。
上面簡單介紹了協變,那麼接下來我們來看逆變是什麼。
其實逆變就是在委託中既要聲明委託類型,也要在委託方法中有實參。
這種在期望傳入基類時允許傳入派生對象的特性叫做逆變。 逆變使用關鍵字in來標記。
具體如下程式碼所示:
delegate void AgeDelegate<in T>(T p);
static void GetAge(People p)
{
Console.WriteLine(p.Age);
}
AgeDelegate<People> ahui = GetAge;
AgeDelegate<AhuiPeople> people = ahui;
people(new AhuiPeople());
Console.WriteLine();
Console.ReadKey();
輸出結果
既然協變和逆變可以使用在委託上,那麼介面上也可以使用,此時也需要使用out和in關鍵字。
寄語
人生短暫,我不想去追求自己看不見的,我只想抓住我能看得見的。
原創不易,給個關注。
我是阿輝,感謝您的閱讀,如果對你有幫助,麻煩點贊、轉發 謝謝。