日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C#泛型接口的協變和逆變_C#教程

作者:青草堂 ? 更新時間: 2022-06-12 編程語言

1、什么是協變、逆變?

假設:TSub是TParent的子類。
協變:如果一個泛型接口IFoo,IFoo可以轉換為IFoo的話,我們稱這個過程為協變,IFoo支持對參數T的協變。
逆變:如果一個泛型接口IFoo,IFoo可以轉換為IFoo的話,我們稱這個過程為逆變,IFoo支持對參數T的逆變。

2、為什么要有協變、逆變?

通常只有具備繼承關系的對象才可以發生隱式類型轉換,如Base b=new sub()。
協變和逆變可以使得更多的類型之間能夠實現隱式類型轉換、類型安全性有了保障。

3、為什么泛型接口要引入協變、逆變?

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

4、為什么支持協變的參數只能用于方法的返回值?支持逆變的參數只能用于方法參數?

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

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

我們看一下協變的過程:IFoo轉換成IFoo

  • Method1:將TSub替換成TParent,Method1顯然存在 TParent到TSub的轉換。
  • Method2:返回值類型從TSub換成了TParent,是類型安全的。

所以支持協變的參數只能用在方法的返回值中。

再看一下逆變的過程:IFoo轉換成IFoo。

  • Method1:將TParent替換成TSub,Method1存在 TSub到TParent的轉換,是類型安全的。
  • Method2:返回值類型從TParent換成了TSub,是不安全的。

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

5、泛型接口支持協變、逆變和不支持協變、逆變的對比?

這其實是對3個問題的補充。

定義一個接口IFoo,既不支持協變,也不支持逆變。

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

實現接口IFoo

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

定義一個接口IBar支持對參數T的協變

    interface IBar
    {
        T Method();
    }

實現接口IBar

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

?定義一個接口IBaz支持對參數T的逆變

    interface IBaz
    {
        void Method(T param);
    }

實現接口IBaz

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

定義兩個有繼承關系的類型,IParent和SubClass。

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

按照協變的邏輯,分別來使用IFoo和IBar。

            //IFoo 不支持對參數T的協變
            IFoo foo_sub = new FooClass();
            IFoo foo_parent = foo_sub;//編譯錯誤

            //IBar 支持對參數T的協變
            IBar bar_sub = new BarClass();
            IBar bar_parent = bar_sub;

foo_parent?=?foo_sub 會提示編譯時錯誤“無法將類型“IFoo”隱式轉換為“IFoo”。存在一個顯式轉換(是否缺少強制轉換?)”

按照逆變的邏輯,分別來使用IFoo和IBaz。

            //IFoo 對參數T逆變不相容
            IFoo foo_parent = null;
            IFoo foo_sub = foo_parent;//編譯錯誤

            //IBaz 對參數T逆變相容
            IBaz baz_parent = null;
            IBaz baz_sub = baz_parent;

?foo_sub?=?foo_parent 會提示編譯時錯誤“無法將類型“IFoo”隱式轉換為“IFoo”。存在一個顯式轉換(是否缺少強制轉換?)”

6、.NET4.0對IEnumerable接口的修改?

2.0中的定義:

    public interface IEnumerable : IEnumerable
    {
        IEnumerator GetEnumerator();
    }

4.0中的定義:

    public interface IEnumerable : IEnumerable
    {
        IEnumerator GetEnumerator();
    }

可以看到4.0中增加了對協變的支持。

可以在兩個版本試下, 下面的語句在2.0下會報錯。

    List subarr = new List();
    IEnumerable parentarr = subarr;

原文鏈接:https://www.cnblogs.com/tenghoo/archive/2012/12/04/interface_covariant_contravariant.html

欄目分類
最近更新