五分鐘看完,徹底理解協變逆變

其實這是c#的老知識點了,但是今天發現同事對這個竟然還一知半解,就和他們講解了下,順便也回顧了下,同事我也把我對這個的全部理解,融化成幾分鐘的講解,保證大家5分鐘內全部理解,看不懂來打我。

協變、逆變 解決的問題

泛型類型轉換

比如Person類是Student的父類,我們平時可以直接:

Person A = new Student();

這是所謂的隱式轉換,相信百分之999.99%的人都知道。
然後隨着大家寫代碼越來越多,就會遇到這樣的場景。

//我有一個集合
//我手上有一批學生
IEnumerable<Student> students = new List<Student>();
//我要他們先做人
IEnumerable<Person> peoples = students;

第一次看到這種代碼,其實哪怕你一點不知道協變,逆變,你也覺得這是一段正常不過的代碼,因爲每個學生都是人,都可以直接轉成 這個類型,那我一批學生不就是一批人嗎。是的,你這樣想絕對沒錯,不然微軟怎麼會能讓你這樣寫沒問題還編譯通過呢?
但是如果我自己寫一個:

//定義一個工作的泛型接口
public interface IWork<T> 
{
            
}

實現類
public class Work<T> : IWork<T> 
{
            
}

//直接報錯
IWork<Person> work = new Work<Student>();;

現實給了我們當頭一棒,這時候,我們應該找到 IEnumerable,選中然後狠狠的F12去看一下,爲什麼官方的就可以。

我們發現官方在泛型前面多了一個out關鍵字。破案了~
現在我們在我們的代碼中也加入out關鍵字

public interface IWork<out T> 
{
            
}

public class Work<T> : IWork<T> 
{
            
}
IWork<Person> work = new Work<Student>();

OK~代碼正常運行。

原則核心

這裏開始我們挑戰五分鐘速通,如果按照正常博客上來先講概念,別說五分鐘了,可能大家也就迷迷糊糊地看完了,所以我們直接整活。

核心依據

正如數學的發展是從1+1=2作爲開始,我們也需要一些真理來支撐我們講下去。那麼我們的核心依據就是:
里氏替換——C#裏,子類轉父類可以直接隱式轉換
就這麼短,就完事了?對,記住就行!!!

Out/In 輸入輸出?

講到這裏,我們繼續忽悠,out是啥?來個翻譯!不就是輸出嗎?in是啥,不就是輸入嗎?那麼帶入一下,Out不就是返回值嗎,In不就是入參嗎。那不就是方法的特徵麼。(先假設,再假設)

In:那麼根據核心依據,子類轉父類可以直接轉,入參如果限定是Person類型,那麼你給我限定爲Student或者任意的Person類型的派生類,我都是可以接受的,因爲都是安全的,可以直接轉換過來的。

這種從基類轉向派生類的兼容,就是所謂的逆變。
說白了,我讓你給我一個人,你說不行,我給你找個學生,那肯定是滿足需求的。

Out:Out代表的是返回值,根據核心依據,我返回的是Student類型,你說不行,你給我返回Person類型,那我不是笑開花了,我連Student都能返回,你讓我返回父類,那我不是直接轉就過去了,總歸是類型安全的。

這種從派生類轉向基類的兼容,就是所謂的協變。
說白了,我可以造個學生,結果你說給個人就行, 那不是so easy。

In示意圖

Out示意圖

證明

好了,我們說了這麼多,至少證明下In/Out是代表的入參和返回值吧?直接show you code:
當Out作爲返回值時的泛型沒有問題,但是入參就報錯了

當In作爲入參時的泛型沒有問題,但是返回值就報錯了

好了,這還需要再解釋嗎?最後我們總結下,逆變和協變就是讓方法有了泛型類型上的轉換能力,強化了方法的多態能力。

問題點

1.屬性爲啥可以用逆變協變?
屬性不就是get/set方法。
2.爲什麼接口和委託可以用逆變協變,類不行?
拜託你找一下共同點,接口和委託的共同點,都是行爲,也就是方法爲核心。接口裏不能有字段。這也印證了我說的逆變協變最終是爲方法服務的。
之所以類不行,我大概理解是方法和實例是分開的,本身不和實例存儲在一起,也不是每個實例一份,如果逆變和協變可以服務類,那麼會出現同樣的類型,但是每個實例內部的同一個字段的類型都不一樣,這對於存儲和類型安全都是問題。
3.逆變和協變有啥用?
當你...設計問題,我就有遇到,有時候用上能更加優雅或者靈活的寫代碼吧,看你吧,少年。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章