最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

泛型的逆變協(xié)變

2023-04-06 08:13 作者:程序員-王堅(jiān)  | 我要投稿

前編

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

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

IFace<object> item = new Face<string>(); // CS0266public interface IFace<T> { ? ?string Print(T input); }public class Face<T> : IFace<T> { ? ?public string Print(T input) => input.ToString(); }

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

逆變協(xié)變

C#泛型中的逆變(in)協(xié)變(out)對(duì)于不常自定義泛型的開發(fā)來說(可能)是個(gè)很難理解的概念, 簡(jiǎn)單來說其表現(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é)變的關(guān)鍵詞?out, 代表支持協(xié)變, 可以進(jìn)行符合直覺且和諧的轉(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(); }

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

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

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

逆變協(xié)變的作用

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

逆變協(xié)變的限制

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

Q: ? 那我什么時(shí)候可以用逆變, 什么時(shí)候可以用協(xié)變, 這兩個(gè)東西用起來有什么限制?
A: ? 簡(jiǎn)單來說, 有關(guān)泛型輸入的用逆變, 關(guān)鍵詞是in, 有關(guān)泛型輸出的用協(xié)變, 關(guān)鍵詞是out, 如果接口中既有輸入又有輸出, 就不能用逆變協(xié)變
Q: ? 為什么這兩個(gè)不能同時(shí)存在?
A: ??協(xié)變的表現(xiàn)形式為將子類賦值給基類, 當(dāng)進(jìn)行輸出相關(guān)操作時(shí), 輸出的對(duì)象類型為基類, 是將子類轉(zhuǎn)為基類, 你可以說子類是基類;
逆變的表現(xiàn)形式為將基類賦值給子類, 當(dāng)進(jìn)行輸入相關(guān)操作時(shí), 輸入的對(duì)象為子類, 是將子類轉(zhuǎn)為基類, 這個(gè)時(shí)候你也可以說子類是基類;
如果同時(shí)支持逆變協(xié)變, 若先進(jìn)行子類賦值給基類的操作, 此時(shí)輸出的是基類,?子類轉(zhuǎn)為基類并不會(huì)有什么問題, 但進(jìn)行輸入操作時(shí)就是在將基類轉(zhuǎn)為子類, 此時(shí)是無法保證類型安全的;
Q: ? 聽不懂, 能不能舉個(gè)例子給我?
A: ? 假設(shè)?IEnumerable<>?同時(shí)支持逆變協(xié)變,?IEnumerable<object> list = new List<string>();進(jìn)行賦值后,?list中實(shí)際保存的類型是string,?item.First()輸出類型為object, 實(shí)際類型是string, 此時(shí)說stringobject沒有任何問題, 協(xié)變可以正常發(fā)揮作用;
但是如果支持了逆變, 假設(shè)我們進(jìn)行輸入類型的操作,?item.Add()?允許的參數(shù)類型為?object, 可以是任意類型, 但是實(shí)際上支持string類型, 此時(shí)的object絕無可能是string


泛型的逆變協(xié)變的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
若尔盖县| 枣庄市| 连平县| 大方县| 运城市| 浏阳市| 丁青县| 金平| 奉贤区| 英山县| 芜湖市| 虞城县| 开阳县| 义马市| 宜章县| 富顺县| 丰镇市| 宝应县| 邳州市| 开化县| 当涂县| 无为县| 山东省| 安丘市| 福清市| 苏州市| 阿尔山市| 库伦旗| 察哈| 贡觉县| 广河县| 九龙县| 峨眉山市| 枣阳市| 建湖县| 股票| 德昌县| 上林县| 高邮市| 隆化县| 赤水市|