C#中的協(xié)變與逆變小結(jié)
一:什么是協(xié)變與逆變
協(xié)變指能夠使用比原始指定的派生類型的派生程度更大(更具體的)的類型,逆變指能夠使用比原始指定的派生類型的派生程度更?。ú惶唧w的)的類型
只有泛型接口和泛型委托參數(shù)支持協(xié)變和逆變
二:引言
using System;
using System.Collections.Generic;
class MainClass
{
static void Main()
{
object o = "str";
List<object> oList = new List<string>();
IEnumerable<object> strs = new List<string>();
}
}
上面這段代碼中,第一句沒問題,屬于類型安全轉(zhuǎn)換,第二句會報錯,因為這兩個list并沒有繼承關(guān)系,而第三句是正確的,其實在背后,就是協(xié)變和逆變在起作用
三:協(xié)變
協(xié)變在泛型方法的參數(shù)里以out表示,使用out可以在聲明父類泛型參數(shù)的時候使用子類泛型參數(shù)構(gòu)造,out參數(shù)可以單純的理解為輸出,作為返回值例如IEnumerable<T>接口

using System;
using System.Collections.Generic;
class MainClass
{
static void Main()
{
IEnumerable<object> list = new List<string>();
}
}
分析一下上面的代碼為什么是合法的呢?首先雖然是用IEnumerable<object>聲明的,但是是用List<string>構(gòu)造的,列表中的元素是string類型。其次IEnumerable的作用只有遍歷元素,不允許添加操作,所以是合法的,本質(zhì)上就是里氏替換原則
四:逆變
逆變在泛型方法的參數(shù)里以in表示,使用in可以在聲明子類泛型參數(shù)的時候使用父類泛型參數(shù)構(gòu)造,int參數(shù)只能作為傳入值不能作為返回值例如Action<T>委托
![]()
using System;
class MainClass
{
static void Main()
{
Action<string> action = new Action<object>((o)=> { });
action("");
}
}
分析一下上面的代碼為什么是合法的呢?看似是object轉(zhuǎn)換成了string,但實際上使用委托的時候傳入的是一個string類型的參數(shù),然后將string轉(zhuǎn)換成了object,本質(zhì)上還是派生類到基類的轉(zhuǎn)換,所以是類型安全的,本質(zhì)上就是里氏替換原則
五:為什么協(xié)變和逆變是針對泛型接口或泛型委托參數(shù)的?
而不能針對泛型類?
由上可知,協(xié)變和逆變都是定義方法成員的(接口不能定義字段只能定義成員),而方法成員在創(chuàng)建對象時是不涉及到對象內(nèi)存分配的,所以是類型安全的,而泛型類是模板類,類中可以包含字段, 所以是不安全的
using System;
using System.Collections.Generic;
class MainClass
{
static void Main()
{
object o1 = "";//類型安全
string s1 = (string)o1;//非類型安全
IEnumerable<object> o2 = new List<string>();//協(xié)變
Action<string> s2 = new Action<object>((o) => { });//逆變
}
}
六:自定義協(xié)變
using System;
using System.Collections.Generic;
class MainClass
{
static void Main()
{
ICustomCovariant<object> o = new CustomCovariant<string>();
}
}
public interface ICustomCovariant<out T>
{
T Get();
}
public class CustomCovariant< T> : ICustomCovariant<T>
{
public T Get()
{
return default(T);
}
}
七:自定義逆變
using System;
using System.Collections.Generic;
class MainClass
{
static void Main()
{
IContravariant<string> o = new CustomContravariant<object>();
}
}
public interface IContravariant<in T>
{
void Get(T t);
}
public class CustomContravariant<T> : IContravariant<T>
{
public void Get(T t)
{
}
}
八:總結(jié)
——在泛型中,如果確定泛型參數(shù)是只讀或者只寫的,那么就可以使用協(xié)變或者逆變。如果泛型參數(shù)無法確定只讀或只寫,這種類型參數(shù)既不能協(xié)變也不能逆變,只能精確類型匹配 ——在泛型或委托中,如果不使用協(xié)變或逆變,那么泛型類型是一個固定類型,而使用協(xié)變或逆變的話,則泛型類型可以實現(xiàn)多態(tài)化
到此這篇關(guān)于C#中的協(xié)變與逆變的文章就介紹到這了,更多相關(guān)C#協(xié)變與逆變內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實現(xiàn)的文件上傳下載工具類完整實例【上傳文件自動命名】
這篇文章主要介紹了C#實現(xiàn)的文件上傳下載工具類,結(jié)合完整實例形式分析了C#操作文件上傳與下載功能,并且還可針對上傳文件自動命名以避免服務(wù)器中的文件名重復(fù),需要的朋友可以參考下2017-11-11
C#/C++ 通過ODBC連接OceanBase Oracle租戶的詳細(xì)過程
近期我們項目正處于將Oracle數(shù)據(jù)庫遷移到OceanBase Oracle租戶模式的階段,考慮到我們項目采用了C++和C#混合開發(fā),并且使用了多種技術(shù),因此存在多種數(shù)據(jù)庫連接方式,C#連接OceanBase的案例相對較少,因此我特意記錄下這一過程,感興趣的朋友一起看看吧2024-05-05
C#使用foreach遍歷哈希表(hashtable)的方法
這篇文章主要介紹了C#使用foreach遍歷哈希表(hashtable)的方法,是C#中foreach語句遍歷散列表的典型應(yīng)用,非常具有實用價值,需要的朋友可以參考下2015-04-04
C#中參數(shù)數(shù)組、引用參數(shù)和輸出參數(shù)示例詳解
這篇文章主要給大家介紹了關(guān)于C#中參數(shù)數(shù)組、引用參數(shù)和輸出參數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05

