深入理解 C# 協變和逆變

msdn?解釋如下:

協變是指能夠使用與原始指定的派生類型相比,派生程度更大的類型。

逆變則是指能夠使用派生程度更小的類型。

?

解釋的很正確,大致就是這樣,不過不夠直白。

直白的理解:

協變”->”和諧的變”->”很自然的變化”->string->object :協變。

逆變”->”逆常的變”->”不正常的變化”->object->string?逆變。

?

上面是個人對協變和逆變的理解,比起記住那些派生,類型,原始指定,更大,更小之類的詞語,個人認為要容易點。

?

下面是一則笑話:

一個星期的每一天應該這樣念:

星期一 = 忙day;?
星期二 = 求死day;?
星期三 = 未死day;?
星期四 = 受死day;?
星期五 = 福來day;?
星期六 = 灑脫day;?
星期天 = 傷day

?

為了演示協變和逆變,以及之間的區別,請創建控制臺程序CAStudy,手動添加兩個類:

image

因為是演示,所以都是個空類,

只是有一點記住Dog?繼承自Animal,

所以Dog變成Animal?就是和諧的變化(協變),而如果Animal?變成Dog就是不正常的變化(逆變)

?

Main函數中輸入:

image

?

因為Dog繼承自Animal,所以Animal?aAnimal = aDog; aDog?會隱式的轉變為Animal.

但是List<Dog>?不繼承List<Animal>?所以出現下面的提示:

image

?

如果想要轉換的話,應該使用下面的代碼:

List<Animal> lstAnimal2 = lstDogs.Select(d => (Animal)d).ToList();

?

可以看到一個lstDogs?變成lstAnimal?是多么復雜的操作了。

正因如此,所以微軟新增了兩個關鍵字:Out,In,下面是他們的msdn解釋:

image

image

?

協變的英文是:“covariant”,逆變的英文是:“Contravariant

為什么Microsoft選擇的是”Out”?”In”?作為特性而不是它們呢?

?

我個人的理解:

因為協變和逆變的英文太復雜了,并沒有體現協變和逆變的不同,但是out??in?卻很直白。

out:?輸出(作為結果),in:輸入(作為參數)

所以如果有一個泛型參數標記為out,則代表它是用來輸出的,只能作為結果返回,而如果有一個泛型參數標記為in,則代表它是用來輸入的,也就是它只能作為參數。

?

目前out?in?關鍵字只能在接口和委托中使用,微軟使用out??in?標記的接口和委托大致如下:

image

image

先看下第一個IEnumerable<T>

image?

?

和剛開始說的一樣,T?out?標記,所以T代表了輸出,也就是只能作為結果返回。

public?static?void?Main()

{

????Dog?aDog =?new?Dog();

????Animal?aAnimal = aDog;

?

????List<Dog> lstDogs =?new?List<Dog>();

????//List<Animal> lstAnimal = lstDogs;

????List<Animal> lstAnimal2 = lstDogs.Select(d => (Animal)d).ToList();

?

????IEnumerable<Dog> someDogs =?new?List<Dog>();

????IEnumerable<Animal> someAnimals = someDogs;

}

?

因為T只能做結果返回,所以T不會被修改,?編譯器就可以推斷下面的語句強制轉換合法,所以

IEnumerable<Animal> someAnimals = someDogs;

可以通過編譯器的檢查,反編譯代碼如下:

image

?

雖然通過了C#編譯器的檢查,但是il?并不知道協變和逆變,還是得乖乖的強制轉換。

在這里我看到了這句話:

IEnumerable<Animal>?enumerable2?= (IEnumerable<Animal>) enumerable1;

那么是不是可以List<Animal> lstAnimal3 = (List<Animal>)lstDogs;?呢?

想要回答這個問題需要在回頭看看Clr via C#?關于泛型和接口的章節了,我就不解釋了,

答案是不可以。

?

上面演示的是協變,接下來要演示下逆變。

為了演示逆變,那么就要找個in標記的接口或者委托了,最簡單的就是:

clip_image002??

?

Main函數中添加:

Action<Animal> actionAnimal =?new?Action<Animal>(a => {/*讓動物叫*/?});

Action<Dog> actionDog = actionAnimal;

actionDog(aDog);

?

很明顯actionAnimal?是讓動物叫,因為DogAnimal,那么既然Animal?都能叫,Dog肯定也能叫。

?

In?關鍵字:逆變,代表輸入,代表著只能被使用,不能作為返回值,所以C#編譯器可以根據in關鍵字推斷這個泛型類型只能被使用,所以Action<Dog> actionDog = actionAnimal;可以通過編譯器的檢查。

?

再次演示Out關鍵字:

添加兩個類:

public?interface?IMyList<out?T>

{

????T GetElement();

}

?

public?class?MyList<T> :?IMyList<T>

{

????public?T GetElement()

????{

????????return?default(T);

????}

}

?

因為out?關鍵字,所以下面的代碼可以通過編譯

IMyList<Dog> myDogs =?new?MyList<Dog>();

IMyList<Animal> myAnimals = myDogs;

?

將上面的兩個類修改為:

public?interface?IMyList<out?T>

{

????T GetElement();

????void?ChangeT(T t);

}

?

public?class?MyList<T> :?IMyList<T>

{

????public?T GetElement()

????{

????????return?default(T);

????}

?

????public?void?ChangeT(T t)

????{

????????//Change T

????}

}

?

編譯:

image?

因為Tout修飾,所以T只能作為參數。

?

同樣修改兩個類如下:

public?interface?IMyList<in?T>

{

????T GetElement();

????void?ChangeT(T t);

}

?

public?class?MyList<T> :?IMyList<T>

{

????public?T GetElement()

????{

????????return?default(T);

????}

?

????public?void?ChangeT(T t)

????{

????????//Change T

????}

}

?

這一次使用in關鍵字。

編譯:

image?

?

因為用in關鍵字標記,所以T只能被使用,不能作為返回值。

?

最后修改代碼為:

public?interface?IMyList<in?T>

{

????void?ChangeT(T t);

}

?

public?class?MyList<T> :?IMyList<T>

{

????public?void?ChangeT(T t)

????{

????????//Change T

????}

}

?

編譯成功,因為in代表了逆變,所以

IMyList<Animal> myAnimals =?new?MyList<Animal>();

IMyList<Dog> myDogs = myAnimals;

?

可以編譯成功!。






本文轉自LoveJenny博客園博客,原文鏈接:http://www.cnblogs.com/LoveJenny/archive/2012/03/13/2392747.html,如需轉載請自行聯系原作者

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/454563.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/454563.shtml
英文地址,請注明出處:http://en.pswp.cn/news/454563.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

華為mate20能用鴻蒙嗎,華為mate20可以用5g網絡嗎

華為mate20不可以用5g網絡&#xff0c;它是4g手機在2018年上市&#xff0c;當時5g并沒有開始流行&#xff0c;因此mate20是不支持5G的。不過在后來的2019年秋季&#xff0c;華為發布了mate20 x的5g版本&#xff0c;這也是mate20系列里唯一支持5G的&#xff0c;除此之外mate20、…

基本農田衛星地圖查詢_#重慶朝天門#谷歌百度騰訊高德“衛星地圖”PK,谷歌更勝一籌...

截圖自便民查詢網&#xff0c;各家衛星地圖PK&#xff0c;各有千秋~谷歌精確度最高&#xff1a;5m&#xff0c;來福士修建中&#xff0c;嘉陵江是綠的&#xff0c;長江是黃的。兩江交匯處有一條分明的界線。谷歌 5m:20ft谷歌 50m:100ft谷歌 200m:500ft谷歌 300m:1000ft谷歌 500…

軟件開發者面試百問答案,老紫竹研究室出品(已經有64個)

當然&#xff0c;全部是我個人的答案&#xff0c;不代表別人。地址 www.laozizhu.com/program.jsp?typeId104 老紫竹研究室&#xff0c;分享軟件開發的快樂與收獲 ‘ 我這里貼上已經寫好的答案連接。 軟件開發者面試百問答案 - 你需要哪些東西幫助你判斷項目是否符合時間要求…

Python 第三方庫之 Celery 分布式任務隊列

一、Celery介紹和使用&#xff1a; Celery 是一個 基于python開發的分布式異步消息任務隊列&#xff0c;通過它可以輕松的實現任務的異步處理&#xff0c; 如果你的業務場景中需要用到異步任務&#xff0c;就可以考慮使用celery&#xff0c; 舉幾個實例場景中可用的例子: 你想…

windows server 2008 (五)web服務器的搭建和部署

Windows server 2008 web服務器的搭建和部署相對于windows server 2003的IIS6來說&#xff0c;windows server 2008推出的IIS7.0為管理員提供了統一的web平臺&#xff0c;為管理員和開發人員提供了一個一致的web解決方案。并針對安全方面做了改進&#xff0c;可以減少利用自定義…

改裝摩托車

摩托車發動機就是將進入氣缸中的燃料混合氣點燃使其燃燒所產生的熱能變為機械能&#xff0c;并由曲軸將動力通過傳動機構傳給摩托車后輪而變為車輛行駛動力的機械。發動機的進排氣量和氣流速是影響高轉速&#xff08;功率&#xff09;輸出的關鍵因素之一。 發動機工作時氣流的路…

華為鴻蒙os logo,華為鴻蒙OS Logo曝光:Powered by HarmonyOS

IT之家 9 月 13 日消息 9 月 10 日&#xff0c;鴻蒙 OS 2.0 亮相華為開發者大會的主舞臺上&#xff0c;華為常務董事、消費者業務 CEO 余承東表示&#xff0c;鴻蒙 OS 是首個真正為全場景時代打造的分布式操作系統&#xff0c;鴻蒙 OS 2.0 全面使能全場景生態。現在博主 勇氣數…

python判斷語句_詳解Python判斷語句的使用方法

本篇介紹Python判斷語句的使用&#xff0c;主要討論簡單條件語句、多重條件語句和嵌套條件語句&#xff0c;在講解的每個案例中都配有流程圖和代碼說明。通過本篇的學習&#xff0c;可以達成如下目標。 ● 掌握判斷語句的使用規則 ● 判斷語句流程圖的畫法 前面我們學習了Pytho…

迫在眉睫的職業規劃

對于大多數程序員來說&#xff0c;微軟是一家值得崇敬的公司&#xff0c;能夠加入微軟&#xff0c;也是很多程序員的愿望。在付出足夠的努力后&#xff0c;一旦進入了微軟&#xff0c;也就意味著可以和最先進的技術終日為伍&#xff0c;一直沿著技術這條路線走下去了。對嗎&…

js setTimeout 使用方法

在項目過程中遇到一些異步加載和其他js方法沖突的問題&#xff1a; 如圖初始化的時候會加載“商戶基本信息”,修改商戶名稱字段第二個頁面也需要修改&#xff1a; function setSeqAndName(){var pritab2 $("#allTabs").tabs("getTab", 1).find("ifra…

python中分支結構包括哪些_python中的分支結構

python不提供switch語句&#xff0c;但是python可以通過字典實現switch語句的功能 實現方法分兩步&#xff1a; 首先&#xff1a;定義一個地點 其次&#xff1a;調用字典的get()獲取相應的表達式 原始方法&#xff1a; from __future__ import division #內置函數&#xff0c;解…

機器學習算法之 logistic、Softmax 回歸

邏輯回歸本質是分類問題&#xff0c;而且是二分類問題&#xff0c;不屬于回歸&#xff0c;但是為什么又叫回歸呢。我們可以這樣理解&#xff0c;邏輯回歸就是用回歸的辦法來做分類。它是在線性回歸的基礎上&#xff0c;通過Sigmoid函數進行了非線性轉換&#xff0c;從而具有更強…

html上傳預覽圖片原理,關于html中圖片上傳預覽的實現

functionchange() {varpicdocument.getElementById("preview"),filedocument.getElementById("f");//得到后綴名varextfile.value.substring(file.value.lastIndexOf(".")1).toLowerCase();//gif在IE瀏覽器暫時無法顯示if(ext!png&&ext!…

程序員成功之路

程序員成功之路 ——The road ahead for programmer&#xff08;演講稿&#xff09; 一、我很羨慕在座的各位同學&#xff0c;因為你們是中國未來的程序員&#xff0c;而我不是&#xff0c;我一直很遺憾。 比爾蓋茨曾經寫過一本書叫做《未來之路》The road ahead, 那么今天我選…

【溫故知新】——原生js中常用的四種循環方式

一、引言 本文主要是利用一個例子&#xff0c;講一下原生js中常用的四種循環方式的使用與區別&#xff1a; 實現效果&#xff1a; 在網頁中彈出框輸入0 網頁輸出“歡迎下次光臨”在網頁中彈出框輸入1 網頁輸出“查詢中……”在網頁中彈出框輸入2 網頁輸出“取款中……”在…

部署egg需要用到pm2嗎_使用寶塔面板部署校園綜合服務平臺項目

本文檔為校園綜合服務平臺服務端的安裝部署教程&#xff0c;歡迎star小程序端下載地址&#xff1a;https://github.com/landalfYao/help.git后臺服務端下載地址&#xff1a;https://github.com/landalfYao/helpserver.git后臺客戶端下載地址&#xff1a;https://github.com/lan…

機器學習算法之線性回歸

一、什么是回歸算法 回歸算法是一種有監督算法 回歸算法是一種比較常用的機器學習算法&#xff0c;用來建立“解釋”變量(自變量X)和觀測值(因變量Y)之間的關系&#xff1b;從機器學習的角度來講&#xff0c;用于構建一個算法模型(函數)來做屬性(X)與標簽(Y)之間的映射關系&a…

html中怎么寫多選框,如何在HTML中實現“選擇所有”復選框?

checkboxes document.getElementsByName(foo);for(var checkbox in checkboxes)checkbox.checked source.checked;} Toggle AllBar 1 Bar 2Bar 3 Bar 4最新情況&#xff1a;這個for each...in構造在Safari 5或Chrome 5中似乎不起作用&#xff0c;至少在本例中是這樣的。這段代…

Console-算法[for]-國王與老人的六十四格

ylbtech-Arithmetic:Console-算法[for]-國王與老人的六十四格1.A&#xff0c;案例-- -- ylb&#xff1a;算法-- Type:算法[for]-- munu:國王與老人的六十四格-- 20:32 2012/3/16-- 案例&#xff1a;印度有個國王&#xff0c;他擁有超人的權力和巨大的財富。但權力和財富最終讓他…

程序人生感悟

<本來不想寫的&#xff0c;實在不想看到某些人誤人子弟&#xff0c;混淆視聽&#xff0c;耽誤了中國IT的未來&#xff0c;所以一吐為快) 一些人總是發出一些錯誤的聲音&#xff0c;形成了劣勝優汰可怕的現象。他們在誤導著中國&#xff0c;把我們的后繼軍訓練成軟件藍領―…