溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

C#泛型接口的協(xié)變和逆變?cè)趺磳?shí)現(xiàn)

發(fā)布時(shí)間:2022-04-11 15:19:14 來(lái)源:億速云 閱讀:111 作者:iii 欄目:開(kāi)發(fā)技術(shù)

本文小編為大家詳細(xì)介紹“C#泛型接口的協(xié)變和逆變?cè)趺磳?shí)現(xiàn)”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“C#泛型接口的協(xié)變和逆變?cè)趺磳?shí)現(xiàn)”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。

1、什么是協(xié)變、逆變?

假設(shè):TSub是TParent的子類(lèi)。
協(xié)變:如果一個(gè)泛型接口IFoo<T>,IFoo<TSub>可以轉(zhuǎn)換為IFoo<TParent>的話(huà),我們稱(chēng)這個(gè)過(guò)程為協(xié)變,IFoo支持對(duì)參數(shù)T的協(xié)變。
逆變:如果一個(gè)泛型接口IFoo<T>,IFoo<TParent>可以轉(zhuǎn)換為IFoo<TSub>的話(huà),我們稱(chēng)這個(gè)過(guò)程為逆變,IFoo支持對(duì)參數(shù)T的逆變。

2、為什么要有協(xié)變、逆變?

通常只有具備繼承關(guān)系的對(duì)象才可以發(fā)生隱式類(lèi)型轉(zhuǎn)換,如Base b=new sub()。
協(xié)變和逆變可以使得更多的類(lèi)型之間能夠?qū)崿F(xiàn)隱式類(lèi)型轉(zhuǎn)換、類(lèi)型安全性有了保障。

3、為什么泛型接口要引入?yún)f(xié)變、逆變?

基于以上原因的同時(shí)、許多接口僅僅將類(lèi)型參數(shù)用于參數(shù)或返回值。所以支持協(xié)變和逆變后泛型的使用上有了更大的靈活性

4、為什么支持協(xié)變的參數(shù)只能用于方法的返回值?支持逆變的參數(shù)只能用于方法參數(shù)?

“TParent不能安全轉(zhuǎn)換成TSub”,是這兩個(gè)問(wèn)題的共同原因。
我們定義一個(gè)接口IFoo。

    interface IFoo<T>
    {
        void Method1(T param);
        T Method2();
    }

我們看一下協(xié)變的過(guò)程:IFoo<TSub>轉(zhuǎn)換成IFoo<TParent>。

  • Method1:將TSub替換成TParent,Method1顯然存在 TParent到TSub的轉(zhuǎn)換。

  • Method2:返回值類(lèi)型從TSub換成了TParent,是類(lèi)型安全的。

所以支持協(xié)變的參數(shù)只能用在方法的返回值中。

再看一下逆變的過(guò)程:IFoo<TParent>轉(zhuǎn)換成IFoo<TSub>。

  • Method1:將TParent替換成TSub,Method1存在 TSub到TParent的轉(zhuǎn)換,是類(lèi)型安全的。

  • Method2:返回值類(lèi)型從TParent換成了TSub,是不安全的。

所以支持逆變的參數(shù)只能用在方法的參數(shù)中。

5、泛型接口支持協(xié)變、逆變和不支持協(xié)變、逆變的對(duì)比?

這其實(shí)是對(duì)3個(gè)問(wèn)題的補(bǔ)充。

定義一個(gè)接口IFoo,既不支持協(xié)變,也不支持逆變。

    interface IFoo<T>
    {
        void Method1(T param);
        T Method2();
    }

實(shí)現(xiàn)接口IFoo

    public class FooClass<T> : IFoo<T>
    {
        public void Method1(T param)
        {
            Console.WriteLine(default(T));
        }
        public T Method2()
        {
            return default(T);
        }
    }

定義一個(gè)接口IBar支持對(duì)參數(shù)T的協(xié)變

    interface IBar<out T>
    {
        T Method();
    }

實(shí)現(xiàn)接口IBar

    public class BarClass<T> : IBar<T>
    {
        public T Method()
        {
            return default(T);
        }
    }

 定義一個(gè)接口IBaz支持對(duì)參數(shù)T的逆變

    interface IBaz<in T>
    {
        void Method(T param);
    }

實(shí)現(xiàn)接口IBaz

    public class BazClass<T> : IBaz<T>
    {
        public void Method(T param)
        {
            Console.WriteLine(param.ToString());
        }
    }

定義兩個(gè)有繼承關(guān)系的類(lèi)型,IParent和SubClass。

    interface IParent
    {
        void DoSomething();
    }
    public class SubClass : IParent
    {
        public void DoSomething()
        {
            Console.WriteLine("SubMethod");
        }
    }

按照協(xié)變的邏輯,分別來(lái)使用IFoo和IBar。

            //IFoo 不支持對(duì)參數(shù)T的協(xié)變
            IFoo<SubClass> foo_sub = new FooClass<SubClass>();
            IFoo<IParent> foo_parent = foo_sub;//編譯錯(cuò)誤

            //IBar 支持對(duì)參數(shù)T的協(xié)變
            IBar<SubClass> bar_sub = new BarClass<SubClass>();
            IBar<IParent> bar_parent = bar_sub;

foo_parent = foo_sub 會(huì)提示編譯時(shí)錯(cuò)誤“無(wú)法將類(lèi)型“IFoo<SubClass>”隱式轉(zhuǎn)換為“IFoo<IParent>”。存在一個(gè)顯式轉(zhuǎn)換(是否缺少?gòu)?qiáng)制轉(zhuǎn)換?)”

按照逆變的邏輯,分別來(lái)使用IFoo和IBaz。

            //IFoo 對(duì)參數(shù)T逆變不相容
            IFoo<IParent> foo_parent = null;
            IFoo<SubClass> foo_sub = foo_parent;//編譯錯(cuò)誤

            //IBaz 對(duì)參數(shù)T逆變相容
            IBaz<IParent> baz_parent = null;
            IBaz<SubClass> baz_sub = baz_parent;

 foo_sub = foo_parent 會(huì)提示編譯時(shí)錯(cuò)誤“無(wú)法將類(lèi)型“IFoo<IParent>”隱式轉(zhuǎn)換為“IFoo<ISub>”。存在一個(gè)顯式轉(zhuǎn)換(是否缺少?gòu)?qiáng)制轉(zhuǎn)換?)”

6、.NET4.0對(duì)IEnumerable接口的修改?

2.0中的定義:

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

4.0中的定義:

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

可以看到4.0中增加了對(duì)協(xié)變的支持。

可以在兩個(gè)版本試下, 下面的語(yǔ)句在2.0下會(huì)報(bào)錯(cuò)。

    List<SubClass> subarr = new List<SubClass>();
    IEnumerable<IParent> parentarr = subarr;

讀到這里,這篇“C#泛型接口的協(xié)變和逆變?cè)趺磳?shí)現(xiàn)”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI