中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#泛型的逆變協變是什么

發布時間:2023-04-19 11:53:54 來源:億速云 閱讀:102 作者:iii 欄目:開發技術

這篇文章主要介紹“C#泛型的逆變協變是什么”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“C#泛型的逆變協變是什么”文章能幫助大家解決問題。

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

我有個朋友, 在使用的過程中發現一個問題

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

逆變協變

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

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

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

轉到 IEnumerable<> 的定義, 我們可以看到

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

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

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

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

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();
}

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

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

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

逆變協變的作用

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

逆變協變的限制

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

Q: &ensp; 那我什么時候可以用逆變, 什么時候可以用協變, 這兩個東西用起來有什么限制?

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

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

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

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

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

關于“C#泛型的逆變協變是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

博湖县| 梧州市| 新郑市| 元氏县| 万盛区| 沈丘县| 旌德县| 合川市| 巴林左旗| 聂拉木县| 吉隆县| 扎兰屯市| 安康市| 宁波市| 雷波县| 军事| 安达市| 都江堰市| 沿河| 大同市| 湖州市| 东海县| 剑川县| 祁连县| 苏尼特右旗| 大安市| 吴旗县| 彭州市| 兖州市| 平舆县| 图们市| 阜城县| 紫阳县| 安化县| 抚顺县| 绥德县| 衡南县| 通州区| 鄱阳县| 巴马| 桦川县|