泛型--协变与逆变(转)
對于泛型的知識,一直比較模糊,現在有機會整理一下,突發發現C#還有很多你不知道的東東,繼續.NET FrameWork中泛型的協變與逆變:
1. 可變性的類型:協變性和逆變性
可變性是以一種類型安全的方式,將一個對象當做另一個對象來使用。如果不能將一個類型替換為另一個類型,那么這個類型就稱之為:不變量。協變和逆變是兩個相互對立的概念:
- 如果某個返回的類型可以由其派生類型替換,那么這個類型就是支持協變的
- 如果某個參數類型可以由其基類替換,那么這個類型就是支持逆變的。
2. C# 4.0對泛型可變性的支持
在C# 4.0之前,所有的泛型類型都是不變量——即不支持將一個泛型類型替換為另一個泛型類型,即使它們之間擁有繼承關系,簡而言之,在C# 4.0之前的泛型都是不支持協變和逆變的。
C# 4.0通過兩個關鍵字:out和in來分別支持以協變和逆變的方式使用泛型。
3. C#中泛型可變性的限制
1. 不支持類的類型參數的可變性
只有接口和委托可以擁有可變的類型參數。in 和 out 修飾符只能用來修飾泛型接口和泛型委托。
2. 可變性只支持引用轉換
可變性只能用于引用類型,禁止任何值類型和用戶定義的轉換,如下面的轉換是無效的:
- 將 IEnumerable<int> 轉換為 IEnumerable<object> ——裝箱轉換
- 將 IEnumerable<short> 轉換為 IEnumerable<int> ——值類型轉換
- 將 IEnumerable<string> 轉換為 IEnumerable<XName> ——用戶定義的轉換
3. 類型參數使用了 out 或者 ref 將禁止可變性
對于泛型類型參數來說,如果要將該類型的實參傳給使用 out 或者 ref 關鍵字的方法,便不允許可變性,如:
delegate void someDelegate<in T>(ref T t)4. 可變性必須顯式指定
從實現上來說編譯器完全可以自己判斷哪些泛型參數能夠逆變和協變,但實際卻沒有這么做,這是因為C#的開發團隊認為:
必須由開發者明確的指定可變性,因為這會促使開發者考慮他們的行為將會帶來什么后果,從而思考他們的設計是否合理。
5. 注意破壞性修改
在修改已有代碼接口的可變性時,會有破壞當前代碼的風險。例如,如果你依賴于不允許可變性的is或as操作符的結果,運行在.NET 4時,代碼的行為將有所不同。同樣,在某些情況下,因為有了更多可用的選項,重載決策也會選擇不同的方法。所以在對已有代碼引入可變性時要做好足夠的單元測試以及防御措施。
6. 多播委托與可變性不能混用
下面的代碼能夠通過編譯,但是在運行時會拋出 ArgumentException 異常:
Func<string> stringFunc = () => ""; Func<object> objectFunc = () => new object(); Func<object> combined = objectFunc + stringFunc;這是因為負責鏈接多個委托的 Delegate.Combine方法要求參數必須為相同的類型。上面的示例我們可以修改成如下正確的代碼:
Func<string> stringFunc = () => ""; Func<object> defensiveCopy = new Func<object>(stringFunc); Func<object> objectFunc = () => new object(); Func<object> combined = objectFunc + defensiveCopy;?推薦文章:
http://www.cnblogs.com/oujinliang/archive/2009/11/30/1613985.html
IOC推薦:
http://developer.51cto.com/art/201107/276775_all.htm
轉載于:https://www.cnblogs.com/xibei666/p/5451793.html
總結
以上是生活随笔為你收集整理的泛型--协变与逆变(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: parseInt(),parseFloa
- 下一篇: RX