一句話清晰總結協變和逆變
看到過園子里面幾篇協變和逆變的文章,但是總覺得寫得不夠清晰,文章這東西注重要是要把自己想表達的觀點表達出來,這個過程應該是把復雜的東西消化出來從而簡單化,清晰化,而不是故弄玄虛,反其道而行之,下面我們言歸正傳啦。
我們先來看一段MSDN原文給協變,逆變和變體下個定義:
A generic interface or delegate is called variant if its generic parameters are declared covariant or contravariant. Both C# and Visual Basic enable you to create your own variant interfaces and delegates.
如果泛型接口或委托的泛型參數聲明為協變或逆變,則將該泛型接口或委托稱為“變體”。 C# 和 Visual Basic 都允許您創建自己的變體接口和委托。
通俗解釋:
變體定義:帶有協變或逆變參數的泛型接口或委托。也就是說協變和逆變主要關注點在泛型接口或委托。
那什么又是協變和逆變呢?
我們先來看下面一個來自MSDN的例子:
2 IEnumerable<string>strings = new List<string>();
3 IEnumerable<object> objects = strings;
大家看到了么一個聲明為IEnumerable<string>的 接口類型被賦給了一個更低 級別的IEnumerable<object>.
對,這就是協變。再來看一個例子:
class Base
{
public static void PrintBases(IEnumerable<Base> bases)
{
foreach(Base b in bases)
{
Console.WriteLine(b);
}
}
}
class Derived : Base
{
public static void Main()
{
List<Derived> dlist = new List<Derived>();
Derived.PrintBases(dlist);//由于IEnumerable<T>接口是協變的,所以PrintBases(IEnumerable<Base> bases)
//可以接收一個更加具體化的IEnumerable<Derived>作為其參數。
IEnumerable<Base> bIEnum = dlist;
}
}
下面給協變下個定義:
協變:讓一個帶有協變參數的泛型接口(或委托)可以接收類型更加精細化,具體化的泛型接口(或委托)作為參數,可以看成OO中多態的一個延伸。
// Assume that the following method is in the class:
// static void SetObject(object o) { }
Action<object> actObject = SetObject;
Action<string> actString = actObject;
string strHello(“Hello”);
actString(strHello);
大家看到了么?一個聲明為Action<object>的類型被賦給了一個Action<string>,大家都知道,Action<T>接收參數,沒有返回值,所以其中的object和string是其參數,這個過程其實就是參數的約束更加強了,也就是說讓參數類型更加精細化。下面我們來給逆變下個定義:
逆變:讓一個帶有協變參數的泛型接口(或委托)可以接收粒度更粗的泛型接口或委托作為參數,這個過程實際上是參數類型更加精細化的過程。
一句話總結:協變讓一個粗粒度接口(或委托)可以接收一個更加具體的接口(或委托)作為參數(或返回值);逆變讓一個接口(或委托)的參數類型(或返回值)類型更加具體化,也就是參數類型更強,更明確。
通常,協變類型參數可用作委托的返回類型,而逆變類型參數可用作參數類型。 對于接口,協變類型參數可用作接口的方法的返回類型,而逆變類型參數可用作接口的方法的參數類型。

浙公網安備 33010602011771號