可變性是.NET4.0中的一個(gè)新特性,可變性可分為 : 協(xié)變性、逆變性、不可變性.
成都創(chuàng)新互聯(lián)公司秉承實(shí)現(xiàn)全網(wǎng)價(jià)值營(yíng)銷(xiāo)的理念,以專(zhuān)業(yè)定制企業(yè)官網(wǎng),網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì),重慶小程序開(kāi)發(fā)公司,網(wǎng)頁(yè)設(shè)計(jì)制作,成都做手機(jī)網(wǎng)站,成都全網(wǎng)營(yíng)銷(xiāo)推廣幫助傳統(tǒng)企業(yè)實(shí)現(xiàn)“互聯(lián)網(wǎng)+”轉(zhuǎn)型升級(jí)專(zhuān)業(yè)定制企業(yè)官網(wǎng),公司注重人才、技術(shù)和管理,匯聚了一批優(yōu)秀的互聯(lián)網(wǎng)技術(shù)人才,對(duì)客戶(hù)都以感恩的心態(tài)奉獻(xiàn)自己的專(zhuān)業(yè)和所長(zhǎng)。那么在.NET4.0之前是否有可變性? 答案是肯定的,我們可以通過(guò)下面的幾個(gè)實(shí)例來(lái)簡(jiǎn)單的了解一下.NET4.0之前的協(xié)變和逆變.
實(shí)例 1 : 方法參數(shù)的協(xié)變
static void Main(string[] args) { GetProject(new Course()); // Course 繼承自 Project 此處進(jìn)行了協(xié)變 } static void GetProject(Project course) { Console.WriteLine(course.Name); }
實(shí)例 2 : 數(shù)組協(xié)變以及執(zhí)行時(shí)類(lèi)型檢查
Course[] course = new Course[4]; Project[] project = course; project[0] = new Excercise();
在上述代碼中會(huì)拋出異常 "system.ArrayTypeMismatchException",因?yàn)閺腸ourse轉(zhuǎn)換為project會(huì)返回原始引用,所以course和project都是引用的同一個(gè)數(shù)組,對(duì)于數(shù)組而言,它是一個(gè)course數(shù)組,所以會(huì)拒絕存儲(chǔ)對(duì)于非course類(lèi)型的引用。數(shù)組的協(xié)變會(huì)導(dǎo)致類(lèi)型安全性在執(zhí)行時(shí)才能體現(xiàn),而不能在編譯時(shí)體現(xiàn)
可變性種類(lèi)分類(lèi)定義:
協(xié)變 : 說(shuō)明泛型類(lèi)型參數(shù)可以從一個(gè)派生類(lèi)更改為它的基類(lèi),在C#中,是用out關(guān)鍵字標(biāo)記協(xié)變量形式的泛型類(lèi)型參數(shù),協(xié)變量泛型類(lèi)型參數(shù)只能出現(xiàn)在輸出位置,比如作為方法的返回類(lèi)型
逆變 : 說(shuō)明泛型類(lèi)型參數(shù)可以從一個(gè)基類(lèi)更改為它的派生類(lèi),在C#中,是用in關(guān)鍵字標(biāo)記逆變形式的泛型類(lèi)型參數(shù),逆變量泛型類(lèi)型參數(shù)只能出現(xiàn)在輸入位置,比如作為方法的參數(shù)。
不可變 :按引用類(lèi)型傳遞變量,可以看成是ref參數(shù),表示傳入的類(lèi)型必須與參數(shù)本身的類(lèi)型完全一致,傳入方法內(nèi)部的值,將同樣以相同的類(lèi)型輸出。
可變性是以一種類(lèi)型安全的方式,將一個(gè)對(duì)象作為另一個(gè)對(duì)象來(lái)使用,在我們面向?qū)ο缶幊讨?繼承這一特性就很好的體現(xiàn)了對(duì)象的可變性.
任何使用了協(xié)變和逆變的轉(zhuǎn)換都是引用轉(zhuǎn)換,這意味著轉(zhuǎn)換之后將返回相同的引用,它不會(huì)創(chuàng)建新的對(duì)象,只是認(rèn)為現(xiàn)有引用與目標(biāo)類(lèi)型匹配,這與某個(gè)層次中,引用類(lèi)型之間的轉(zhuǎn)換是相同的。
在.NET4.0之前,泛型是不能夠進(jìn)行協(xié)變和逆變的,也就是說(shuō)泛型的協(xié)變和逆變是C#4.0的一個(gè)新特性,泛型的協(xié)變和逆變也是為了保持類(lèi)型的絕對(duì)安全性.
在泛型接口或者委托的聲明中,.NET4.0能夠使用out修飾符來(lái)指定類(lèi)型參數(shù)的協(xié)變性,使用in修飾符來(lái)指定逆變性,聲明完成之后,就可以對(duì)相關(guān)的類(lèi)型進(jìn)行隱式轉(zhuǎn)換了,在接口和委托中,它們的工作方式是完全相同的.
我們使用的兩個(gè)接口 : IEnumberable
更多的泛型協(xié)變接口 : IEnumerable
泛型逆變接口 : IComparer
下面我們通過(guò)實(shí)例來(lái)演示一下接口的泛型可變性
實(shí)例 3 : 查看泛型接口集合IEnumberable
class Project { public static void GetCourseByProjects(IEnumerableprojects) { foreach (var p in projects) { Console.WriteLine(p); } } public string Name { get; set; } } class Course : Project { public static void GetCourse() { List courseList = new List (); Project.GetCourseByProjects(courseList); IEnumerable pList = courseList; } }
在上述代碼中,我們定義了兩個(gè)類(lèi),分別為 : project和course,其中course繼承自project,在project中有一個(gè)方法GetCourseByProject,這個(gè)方法有一個(gè)形參類(lèi)型為 IEnumberable
實(shí)例 4 : 定義泛型接口查看逆變
static void Main(string[] args) { IBasegetCourse = new Derived (); } public class Derived : IBase { public string Name { get; set; } public void GetProject(T t) { Console.WriteLine("獲取到項(xiàng)目"); } } public interface IBase { void GetProject(T t); } class Course : Project { public static void GetCourse() { } }
在上述代碼中,我們定義一個(gè)泛型接口 IBase
IBase
在我們看了,泛型接口的協(xié)變和逆變之后,對(duì)于泛型委托的可變性其實(shí)性質(zhì)是一樣的.我們可以通過(guò)下面兩個(gè)實(shí)例來(lái)演示一下 :
實(shí)例 5 : 委托協(xié)變
public delegate Project GetProject(); static Course GetCourse() { return new Course(); } GetProject projects = GetCourse;
在上述的代碼中,我們首先定義了一個(gè)委托類(lèi)型,getproject, 在GetProject projects = GetCourse,GetCourse是一個(gè)返回值為Course對(duì)象的一個(gè)函數(shù), 此處發(fā)生了協(xié)變,Course類(lèi)型轉(zhuǎn)換為了Project類(lèi)型,子類(lèi)轉(zhuǎn)換為父類(lèi).
實(shí)例 6 : 泛型委托協(xié)變
public delegate T Find(); static void Main(string[] args) { Find getCourse = () => new Course(); // lambda Find getProject = getCourse; // 發(fā)生了協(xié)變 }
在上述的代碼中,我們定義了一個(gè)泛型委托,Find
實(shí)例 7 : 委托中的逆變
public delegate void FindCourse(Course course); static void GetProject(Project pro) { Console.WriteLine(pro.Name); } FindCourse getCourse = GetProject;
在上述的代碼中,首先我們聲明了一個(gè)帶參數(shù)的委托FindCourse,參數(shù)類(lèi)型為 Course , 然后注意在第六行代碼中, 我們將 GetProject這個(gè)方法賦值給了 委托FindCourse,同時(shí),GetProject這個(gè)方法的參數(shù)類(lèi)型為 Project,Project為Course 的基類(lèi),所以在第六行代碼中它發(fā)生了逆變.
實(shí)例 8 : 泛型委托中的逆變
public delegate void Find(T t); Find getProject = p => Console.Write("查看一個(gè)項(xiàng)目"); Find getCourse = getProject;
相信通過(guò)了前面的幾個(gè)實(shí)例,這個(gè)例子也就不難看懂了,在上述的代碼中,我們首先聲明了一個(gè)泛型委托,并且泛型中有一個(gè)in說(shuō)明是可以進(jìn)行逆變,然后在第二行代碼中,我們還是通過(guò)lambda表達(dá)式,創(chuàng)建一個(gè)參數(shù)類(lèi)型為Project的函數(shù),注意第三行代碼, 第三行代碼中將GetProject方法賦值給了getCourse,此處發(fā)生了逆變.
【四】.NET中可變性的好處
1 、更好的代碼復(fù)用性.
通過(guò)剛才的幾個(gè)實(shí)例,我們可以知道,如果在Project下還有Excerise,Test等派生類(lèi)的話(huà), 利用協(xié)變和逆變性,我們就可以直接 Project.GetCourseByProjects(ExceriseList); (協(xié)變了) . IBase
2、更好的保持了泛型的類(lèi)型安全性
首先,協(xié)變和逆變是通過(guò)out,in來(lái)指定的,編譯器是不知道那種形式是協(xié)變那種形式是逆變的,通過(guò)out(輸出參數(shù))和in(輸入?yún)?shù)),來(lái)指定參數(shù)的輸入輸出類(lèi)型這一形式,很好的保持了泛型的類(lèi)型安全性.
PS : ref 也是一種,用來(lái)指定不變性,指定要求傳入什么類(lèi)型的就是什么類(lèi)型,在一般我們開(kāi)發(fā)過(guò)程中,通過(guò)都是通過(guò)這樣的形式來(lái)傳參的,比如:
實(shí)例 9 : ref雙向傳值,要求實(shí)參類(lèi)型必須與形參類(lèi)型完全一致
Project p = new Project(); GetProject( ref p); public static void GetProject(ref Project project) { Console.WriteLine(project.Name); }
調(diào)用方法所傳入的類(lèi)型必須要與方法要求的參數(shù)類(lèi)型完全一致
平日里我們覺(jué)得一些比較難的技術(shù)點(diǎn),當(dāng)我們花費(fèi)一些時(shí)間去學(xué)習(xí),去總結(jié),去思考一下.會(huì)發(fā)現(xiàn)其實(shí)并不是我們想象中那么難, 難得是我們下定決心去做的那份意念而已.
通過(guò)本文我們了解到了協(xié)變性、逆變性、不變性的定義,以及它是通過(guò)一種什么樣的形式來(lái)實(shí)現(xiàn)的, 另外通過(guò)實(shí)例我們也可以想到如果用好了它,也會(huì)給我的開(kāi)發(fā)帶來(lái)事半功倍的效果。使我們的代碼更加優(yōu)雅、提高程序可擴(kuò)展性以及復(fù)用性,同時(shí)這不也是一種多態(tài)的體現(xiàn)嗎?
通過(guò)協(xié)變和逆變也有一些限制,這可能也是因?yàn)樵O(shè)計(jì)者出于類(lèi)型安全性的方面考慮,它是不支持類(lèi)的類(lèi)型參數(shù)的可變性,只有接口和委托可以擁有可變的類(lèi)型參數(shù). 可變性只支持引用轉(zhuǎn)換.
如果你覺(jué)得本文對(duì)你有幫助的話(huà),請(qǐng)點(diǎn)右下角的推薦,或者直接關(guān)注我,后續(xù)將不斷更新.NET解析這一系列的文章....
作者:劉彬
出處:http://albin.blog.51cto.com/
本文版權(quán)歸作者和51CTO共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
創(chuàng)新互聯(lián)www.cdcxhl.cn,專(zhuān)業(yè)提供香港、美國(guó)云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開(kāi)啟,新人活動(dòng)云服務(wù)器買(mǎi)多久送多久。