一句話清晰總結協變(covariant)和逆變 (contravariant)

作者: SolidMango  來源: 博客園  發布時間: 2011-11-09 15:58  閱讀: 9908 次  推薦: 5   原文鏈接   [收藏]  

  看到過園子里面幾篇協變和逆變的文章,但是總覺得寫得不夠清晰,文章這東西最重要的是要把自己想表達的觀點表達出來,這個過程應該是把復雜的東西消化出來從而簡單化,清晰化,而不是故弄玄虛,反其道而行之,下面我們言歸正傳啦。

  我們先來看一段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的例子:

// 協變
IEnumerable<string> strings = new List<string>();
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; 
//委托actString中以后要使用更加精細化的類型string不能再使用object啦!
string strHello(“Hello”); 
actString(strHello);

  大家看到了么?一個聲明為Action<object>的類型被賦給了一個Action<string>,大家都知道,Action<T>接收參數,沒有返回值,所以其中的object和string是其參數,這個過程其實就是參數的約束更加強了,也就是說讓參數類型更加精細化。下面我們來給逆變下個定義:

  逆變:讓一個帶有協變參數的泛型接口(或委托)可以接收粒度更粗的泛型接口或委托作為參數,這個過程實際上是參數類型更加精細化的過程。

  總結

  一句話總結:協變讓一個粗粒度接口(或委托)可以接收一個更加具體的接口(或委托)作為參數(或返回值);逆變讓一個接口(或委托)的參數類型(或返回值)類型更加具體化,也就是參數類型更強,更明確。

  通常,協變類型參數可用作委托的返回類型,而逆變類型參數可用作參數類型。對于接口,協變類型參數可用作接口的方法的返回類型,而逆變類型參數可用作接口的方法的參數類型。

5
12
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()