程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 一個簡單例子理解C#的協變和逆變,

一個簡單例子理解C#的協變和逆變,

編輯:C#入門知識

一個簡單例子理解C#的協變和逆變,


 

關於協變逆變,SolidMango的解釋是比較可取的。有了協變,比如,在需要返回IEnumerable<object>類型的時候,可以使用IEnmerable<string>來替代;有了逆變,比如,在需要接收IComparable<string>類型形參方法中,可以使用IComparable<object>類型實參來替代。

 

協變

 

先來體會協變。有2個具有繼承關系的父類和子類。

 

    public class Animal
    {
        public string Name { get; set; }
    }
    public class Dog : Animal
    {
        public Dog(string dogName)
        {
            Name = dogName;
        }
    }

 

現在有一個幫助類的方法的形參類型是父類集合IEnumerable<Animal>。

 

    public class MyHelper
    {
        public void PrintAnimalNames(IEnumerable<Animal> animals)
        {
            foreach (var animal in animals)
            {
                Console.WriteLine(animal.Name);
            }
        }
    }

 

有了協變,可以在PrintAnimalNames方法中傳入IEnumerable<Dog>類型的實參替代IEnumerable<Animal>類型。

 

        static void Main(string[] args)
        {
            List<Dog> dogs = new List<Dog>()
            {
                new Dog("小狗petty"),
                new Dog("小狗lily")
            };
            //協變
            IEnumerable<Animal> animals = dogs;
            MyHelper myHelper = new MyHelper();
            myHelper.PrintAnimalNames(animals);
            Console.ReadKey();
        }


可見,在方法中基於基類接口類型的形參,調用該方法的時候可以傳入派生類接口類型的實參。       

 

逆變


再來體會逆變。依然是2個具有繼承關系的父類和子類。

 

    public class Animal 
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    public class Cat : Animal
    {
        public Cat(string catName, int catAge)
        {
            Name = catName;
            Age = catAge;
        }
    }

 

現在,我們想比較基類Animal的兩個實例,為此,有必要專門寫一個類讓他實現IComparer<Animal>接口。

 

    public class AnimalSizeComparator : IComparer<Animal>
    {
        public int Compare(Animal x, Animal y)
        {
            if (x != null && y != null)
            {
                if (x.Age > y.Age)
                {
                    return 1;
                }
                else if (x.Age == y.Age)
                {
                    return 0;
                }
                else
                {
                    return -1;
                }
            }
            else
            {
                return -1;
            }
        }
    }

 

在幫助類中的方法中,針對Cat進行比較,方法接收IComparer<Cat>類型的形參。

 

    public class MyHelper
    {
        public void CompareCats(IComparer<Cat> catComparer)
        {
            var cat1 = new Cat("小貓1",1);
            var cat2 = new Cat("小貓2",2);
            if (catComparer.Compare(cat2, cat1) > 0)
            {
                Console.WriteLine("小貓2勝出");
            }
            else
            {
                Console.WriteLine("小貓1勝出");
            }
        }
    }    

 

有了逆變,客戶端調用MyHelper的CompareCats方法時,可以傳入IComparer<Animal>類型的實參。

 

            IComparer<Animal> animalComparer = new AnimalSizeComparator();
            MyHelper myHelper = new MyHelper();
            myHelper.CompareCats(animalComparer);
            Console.ReadKey(); 

 

可見,在方法中基於派生類接口類型的形參,調用該方法的時候可以傳入基類接口類型的實參。 

      

總結:在本篇的場景中,派生類接口替代父類接口,稱之為協變;父類接口代替派生類接口,稱之為逆變。

  1. 上一頁:
  2. 下一頁: