c语言编程笔录

首页 >   > 笔记大全

笔记大全

C中的协变与逆变接口怎么实现

更新时间:2023-10-05

什么是协变和逆变

在程序中,我们经常会看到类之间的继承关系,从基类派生出子类。由于子类本身也包含了基类的成员和方法,因此我们可以把子类的对象赋值给基类的变量。例如:

    class Animal {}
    class Dog : Animal {}
    Dog dog = new Dog();
    Animal animal = dog; // 正确的赋值操作

协变和逆变则是在这种基本的继承关系上,对派生类和基类之间的类型转换进行限制。

协变,实现可以将接口作为一个方法返回类型,它使方法能够返回比它所定义的返回类型更具体的类型。这里的具体类型是指实现接口的类型是传递给方法的类型的基类型的派生类型。

逆变,则是相反的操作。通过这种方法,参数类型基下限的更改可以允许接受另一个比定义的参数类型更一般的值。逆变的接口能让我们的方法中接收到更具抽象性的类型。

协变和逆变的实现机制

协变和逆变是依赖于数组的协变和逆变来实现的。数组是.net中唯一支持协变和逆变的类型。

协变是允许将一个数组类型的元素类型转换成一个更加派生的类型的过程。

例如:

    class Animal {}
    class Dog : Animal {}
    Dog[] dogs = new Dog[1];
    Animal[] animals = dogs; // 协变操作

逆变则是基于输入形参的类型可以被赋值给具有更具体类型的形参来实现的,这样做,我们就可以把一个更加具体的类型传递给输入参数。

例如:

    class Animal {}
    class Dog : Animal {}
    Action dogDelegate = (d) => Console.WriteLine(d);
    Action animalDelegate = dogDelegate; // 逆变操作

这里,我们看到DogsDelegate接受Dog类型,而AnimalsDelegate接受的是Animal类型。

协变接口的实现

我们创建了Animal接口,实现了协变接口。

    public interface IAnimal
    {
        T Get();
    }

    public class Animal
    {
        public string Name { get; set; }
    }

    public class Dog : Animal
    {
        public string Breed { get; set; }
    }

    public class AnimalGroup : IAnimal
    {
        public Animal Get()
        {
            return new Animal()
            {
                Name = "Animal Group"
            };
        }
    }

    public class DogGroup : IAnimal
    {
        public Dog Get()
        {
            return new Dog()
            {
                Name = "Dog Group",
                Breed = "Golden Retriever"
            };
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            IAnimal animalGroup = new AnimalGroup();
            IAnimal dogGroup = animalGroup; // 协变接口实现
            Console.WriteLine(dogGroup.Get().Name); // 输出Animal Group
        }
    }

在上面的例子中,我们已经实现了带有一个协变接口参数的程序,我们可以指定DogGroup类来实现IAnimal<Dog>,然后通过直接将这个对象赋给IAnimal<Animal>来实现协变功能。

逆变接口的实现

我们创建了Animal接口,实现了逆变接口。

    public interface IAnimal
    {
        void Add(T animal);
    }

    public class Animal
    {
        public string Name { get; set; }
    }

    public class Dog : Animal
    {
        public string Breed { get; set; }
    }

    public class AnimalGroup : IAnimal
    {
        public void Add(Animal animal)
        {
            Console.WriteLine($"Add an animal: {animal.Name}");
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            IAnimal dogGroup = new AnimalGroup(); // 逆变接口实现
            dogGroup.Add(new Dog()
            {
                Name = "Lucky",
                Breed = "Poodle"
            });
        }
    }

在上面的例子中,我们已经实现了一个带有一个逆变接口参数的程序,我们可以通过指定一个AnimalGroup类来实现IAnimal<Animal>,然后通过直接将它分配给IAnimal<Dog>,来实现逆变的功能。

总结

协变和逆变是C#类型系统提供的两种运行时类型检查机制。协变和逆变是依赖于数组的协变和逆变来实现的,是.net强类型系统的一部分,这意味着.NET中的数组是唯一允许协变和逆变的类型。

协变和逆变不仅可以帮助我们编写更加灵活的代码,而且可以提高代码整体的可读性和可维护性。