最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#泛型的逆變協(xié)變之個人理解

 更新時間:2023年04月05日 13:06:31   作者:崩壞的領航員  
這篇文章主要介紹了C#泛型的逆變協(xié)變之個人理解,需要的朋友可以參考下

一般來說, 泛型的作用就類似一個占位符, 或者說是一個參數(shù), 可以讓我們把類型像參數(shù)一樣進行傳遞, 盡可能地復用代碼。

我有個朋友, 在使用的過程中發(fā)現(xiàn)一個問題

IFace<object> item = new Face<string>(); // CS0266

public interface IFace<T>
{
    string Print(T input);
}
public class Face<T> : IFace<T>
{
    public string Print(T input) => input.ToString();
}

Q:   string 明明是 object 的子類, 為啥這樣賦值會報錯呢???
A:   因為 Face<string> 實現(xiàn)的是 IFace<string>, 而 IFace<string> 并不是 IFace<object> 的子類
Q:   但是 string 是 object 的子類啊, IFace<string> 可不就是 IFace<object> 嗎?
A:   如果只論接口定義, 看起來確實是這樣的, 但是你要看內(nèi)部實現(xiàn)的方法, IFace<string> 的 Print 方法參數(shù)是 string, 但是 IFace<object> 的 Print 參數(shù)是 object, 如果上面的賦值可以成立, 就意味著允許 Print(string input) 方法傳遞任意類型的對象, 這樣明顯是有問題的
Q:   但是我曾經(jīng)看到過 IEnumerable<object> list = new List<string>(); 這個為什么就可以
A:   這就要講到C#泛型里的逆變協(xié)變
Q:   細嗦細嗦

逆變協(xié)變

C#泛型中的逆變(in)協(xié)變(out)對于不常自定義泛型的開發(fā)來說(可能)是個很難理解的概念, 簡單來說其表現(xiàn)形式如下

逆變(in): I<子類> = I<父類>協(xié)變(out): I<父類> = I<子類>

上面例子中提到的 IEnumerable<object> list = new List<string>(); 體現(xiàn)的是協(xié)變, 符合一般直覺, 整體上看起來就像是將子類賦值給基類

轉(zhuǎn)到 IEnumerable<> 的定義, 我們可以看到

public interface IEnumerable<out T> : IEnumerable
{
    new IEnumerator<T> GetEnumerator();
}

泛型 T 之前加了協(xié)變的關鍵詞 out, 代表支持協(xié)變, 可以進行符合直覺且和諧的轉(zhuǎn)化

前編中提到的代碼例子不適用并且也不能改造成協(xié)變, 只適合使用逆變

相比于符合直覺且和諧協(xié)變逆變不符合直覺并且別扭

IFace<string> item = new Face<object>();

public interface IFace<in T>
{
    string Print(T input);
}
public class Face<T> : IFace<T>
{
    public string Print(T input) => input.ToString();
}

這是一個逆變的例子, 與協(xié)變相似, 需要在泛型 T 之前加上關鍵詞 in

對比上方的協(xié)變逆變看起來就像是將基類賦值給子類, 但這其實符合里氏代換的

當我們調(diào)用 item.Print 時, 看起來允許傳入的參數(shù)為 string 類型, 而實際上最終調(diào)用的 Face<object>.Print 是支持 object 的, 傳入 string 類型的參數(shù)沒有任何問題

逆變協(xié)變的作用

逆變(in)協(xié)變(out)的作用就是擴展泛型的用法, 幫助開發(fā)者更好地復用代碼, 同時通過約束限制可能會出現(xiàn)的破壞類型安全的操作

逆變協(xié)變的限制

雖然上面講了逆變(in)協(xié)變(out)看起來是什么樣的, 但我的那個朋友還是有些疑問

Q:   那我什么時候可以用逆變, 什么時候可以用協(xié)變, 這兩個東西用起來有什么限制?

A:   簡單來說, 有關泛型輸入的用逆變, 關鍵詞是in, 有關泛型輸出的用協(xié)變, 關鍵詞是out, 如果接口中既有輸入又有輸出, 就不能用逆變協(xié)變

Q:   為什么這兩個不能同時存在?

A:   協(xié)變的表現(xiàn)形式為將子類賦值給基類, 當進行輸出相關操作時, 輸出的對象類型為基類, 是將子類轉(zhuǎn)為基類, 你可以說子類是基類;
逆變的表現(xiàn)形式為將基類賦值給子類, 當進行輸入相關操作時, 輸入的對象為子類, 是將子類轉(zhuǎn)為基類, 這個時候你也可以說基類是子類;
如果同時支持逆變協(xié)變, 若先進行子類賦值給基類的操作, 此時輸出的是基類, 子類轉(zhuǎn)為基類并不會有什么問題, 但進行輸入操作時就是在將基類轉(zhuǎn)為子類, 此時是無法保證類型安全的;

Q:   聽不懂, 能不能舉個例子給我?

A:   假設 IEnumerable<> 同時支持逆變協(xié)變, IEnumerable<object> list = new List<string>();進行賦值后, list中實際保存的類型是stringitem.First()輸出類型為object, 實際類型是string, 此時說stringobject沒有任何問題, 協(xié)變可以正常發(fā)揮作用;
但是如果支持了逆變, 假設我們進行輸入類型的操作, item.Add() 允許的參數(shù)類型為 object, 可以是任意類型, 但是實際上支持string類型, 此時的object絕無可能是string

Q:   好像聽懂了一點了, 我以后慢慢琢磨吧

兩者的限制簡單總結就是

輸入的用逆變

??????????????輸出的用協(xié)變

相關文章

  • C#通過標簽軟件Bartender的ZPL命令打印條碼

    C#通過標簽軟件Bartender的ZPL命令打印條碼

    這篇文章介紹了C#通過標簽軟件Bartender的ZPL命令打印條碼,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-01-01
  • c# 動態(tài)加載dll文件,并實現(xiàn)調(diào)用其中的簡單方法

    c# 動態(tài)加載dll文件,并實現(xiàn)調(diào)用其中的簡單方法

    下面小編就為大家?guī)硪黄猚# 動態(tài)加載dll文件,并實現(xiàn)調(diào)用其中的簡單方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • C#實現(xiàn)把圖片轉(zhuǎn)換成二進制以及把二進制轉(zhuǎn)換成圖片的方法示例

    C#實現(xiàn)把圖片轉(zhuǎn)換成二進制以及把二進制轉(zhuǎn)換成圖片的方法示例

    這篇文章主要介紹了C#實現(xiàn)把圖片轉(zhuǎn)換成二進制以及把二進制轉(zhuǎn)換成圖片的方法,結合具體實例形式分析了基于C#的圖片與二進制相互轉(zhuǎn)換以及圖片保存到數(shù)據(jù)庫的相關操作技巧,需要的朋友可以參考下
    2017-06-06
  • C#中Write()和WriteLine()的區(qū)別分析

    C#中Write()和WriteLine()的區(qū)別分析

    這篇文章主要介紹了C#中Write()和WriteLine()的區(qū)別分析,需要的朋友可以參考下
    2020-11-11
  • C#中的Task使用方式

    C#中的Task使用方式

    本文介紹了C#中的Task,這是一種異步編程模型,允許你在不阻塞主線程的情況下執(zhí)行耗時的操作,文章詳細介紹了如何創(chuàng)建、等待、處理異常、延續(xù)以及并行執(zhí)行Task
    2024-12-12
  • C#?崩潰異常中研究頁堆布局的詳細過程

    C#?崩潰異常中研究頁堆布局的詳細過程

    最近遇到一位朋友的程序崩潰,發(fā)現(xiàn)崩潰點在富編輯器 msftedit 上,這個不是重點,重點在于發(fā)現(xiàn)他已經(jīng)開啟了 頁堆,由于 頁堆 和 NT堆 的內(nèi)存布局完全不一樣,這一篇結合我的了解以及 windbg 驗證來系統(tǒng)的介紹下 頁堆,需要的朋友可以參考下
    2022-10-10
  • 完美解決c# distinct不好用的問題

    完美解決c# distinct不好用的問題

    這篇文章主要介紹了完美解決c# distinct不好用的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • C#多線程中如何運用互斥鎖Mutex

    C#多線程中如何運用互斥鎖Mutex

    這篇文章主要為大家詳細介紹了C#多線程中如何運用互斥鎖Mutex,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • C#中的is和as操作符區(qū)別小結

    C#中的is和as操作符區(qū)別小結

    這篇文章主要介紹了C#中的is和as操作符區(qū)別小結,is是驗證操作對象是不是自己希望的,as是將對象轉(zhuǎn)換成指定類型,需要的朋友可以參考下
    2015-01-01
  • C#實現(xiàn)從PDF中提取表格的方法詳解

    C#實現(xiàn)從PDF中提取表格的方法詳解

    PDF是辦公中比較常見的一種文件格式,在工作中應用也越來越普遍。今天為大家介紹一種通過C#/VB.NET代碼從PDF中提取表格內(nèi)容的方法,感興趣的可以動手嘗試一下
    2022-08-08

最新評論

手游| 揭西县| 额敏县| 塔河县| 油尖旺区| 山东| 靖江市| 榕江县| 牡丹江市| 新龙县| 霍林郭勒市| 高平市| 桑植县| 砚山县| 富源县| 九台市| 七台河市| 文安县| 阿荣旗| 长岭县| 三河市| 海宁市| 梨树县| 盘锦市| 中阳县| 布尔津县| 民和| 县级市| 佛冈县| 淮阳县| 鱼台县| 呼玛县| 本溪市| 桑植县| 汉沽区| 潼关县| 巴南区| 赤城县| 山丹县| 京山县| 汤阴县|