您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關c#中協變與逆變的定義是什么,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
基本概念
協變:能夠使用比原始指定的派生類型的派生程度更大(更具體)的類型。例如 IFoo<父類> = IFoo<子類>
逆變:能夠使用比原始指定的派生類型的派生程度更新(更抽象)的類型。例如 IBar<子類> = IBar<父類>
關鍵字out和in
協變和逆變在泛型參數中的表現方式,out關鍵字表示協變,in關鍵字表示逆變。二者只能在泛型接口或者委托中使用。
理解協變和逆變
看完上面的定義是不是一臉懵逼~~~。看不懂就對了,且定義語句的歧義性很大。讓我們大腦趕緊清空下!!首先記住一點明確的概念,類的多態展示一定是通過基類來表示,派生的具體類都是可轉化為基類,而不能走相反的流程。
下面我們用代碼直觀的表現下協變和逆變。
public class Animal { public void Eat() { } } public class Dog : Animal { public void Run() { } }
這是一段很簡單的子類和父類的關系,我們進行一下簡單的轉化,應該很好理解,Dog子類可以用Animal父類展示,反過來則不可以,會編譯錯誤。
Dog dog = new Dog(); Animal animal = dog; //error 編譯錯誤 //Dog dog2 = animal;
那么我們做一點變化。
List<Dog> dogs = new List<Dog>(); //error 編譯錯誤 //List<Animal> animals_2 = dogs; IEnumerable<Dog> dogs_2 = dogs; IEnumerable<Animal> animals = dogs_2;
感覺到一點問題沒?Dog子類可以用Animal父類展示,使用List泛型就不可以了,但是IEnumerable泛型又可以。List<>和IEnumerable<>有什么不同?我們看下二者的定義即可發現端倪。
//IList定義 public interface IList<[NullableAttribute(2)] T> : ICollection<T>, IEnumerable<T>, IEnumerable {} //和IEnumerable定義 public interface IEnumerable<[NullableAttribute(2)] out T> : IEnumerable {}
區別就在于 IEnumerable的泛型參數用了out協變標注,所以可以做正確的轉換。 這里也可以理解出什么時候需要使用in、out關鍵字:當你設計帶有泛型的基類且泛型類型可能存在擴展時,則需要考慮使用in或者out關鍵字修飾。
我們再看看官方的Action<>和Func<>類對協變和逆變的使用,先看定義:
public delegate void Action<[NullableAttribute(2)] in T>(T obj); public delegate TResult Func<[NullableAttribute(2)] in T, [NullableAttribute(2)] out TResult>(T arg);
Action的泛型類型是入參,用in表示逆變,Func的第二個泛型類型TResult是出參,用out表示協變。
那么這樣看起來對in、out關鍵字的認識就很簡單明了了。看看轉換示例:
Action<Dog> action_dog = d => d.Run(); Action<Animal> action_animal = a => a.Eat(); //error 編譯錯誤。in //Action<Animal> action_animal_2 = action_dog; //Action泛型多態化 Action<Dog> action_dog_2 = action_animal; Func<int, Dog> func_dog = a => { return new Dog(); }; Func<int, Animal> func_animal = a => { return new Animal(); }; //Func泛型多態化 Func<int, Animal> func_animal_2 = func_dog; //error 編譯錯誤。out //Func<int, Dog> func_dog_2 = func_animal;
注意注釋編譯錯誤的語句,符合上面我們轉換的規則。對于入參,擴展類可以替代基類參數輸入,用in修飾;對于出參,擴展類可以替代基類返回輸出,用out修飾。相反則都不可以。
最后簡單總結下:
什么是協變/逆變?不要去想官方定義!!!!只要記住out是協變,in是逆變即可。
為什么需要使用協變-out、逆變-in。在泛型或委托中,如果不使用協變/逆變,那么泛型類型一個精確的、固定的某一類型。而使用協變/逆變的話,則泛型類型可以實現多態化。但必須區分入參使用in,出參使用out。
以上就是c#中協變與逆變的定義是什么,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。