一文带你了解C#中的协变与逆变
什么是协变与逆变
在程序设计中,经常需要对类进行继承和实现接口的操作。在这样的过程中,我们通常会遇到这样的问题:子类或者实现接口的类的泛型参数类型和父类的泛型参数类型不匹配。而“协变”和“逆变”就是解决这样的问题的方法。
协变和逆变是 C# 4.0 引入的两个关键技术,可以让我们更加灵活地使用泛型。在 C# 中,协变和逆变可以用于委托、接口和数组等这些数据结构。
协变
协变是指在保持类型安全的前提下,可以将从泛型类派生的子类对象作为基类对象使用。也就是说,对于一个泛型类型 T
我们可以理解一个泛型类的协变是这个泛型类泛型参数的类型可以隐式向上转换。例如:
public interface IAnimal { }
public class Animal { }
public class Dog : Animal, IAnimal { }
public interface ITest<out T> where T : IAnimal
{
T Get();
}
public class Test<T> : ITest<T> where T : IAnimal
{
public T Get()
{
return default(T);
}
}
public class Program
{
public static void Main(string[] args)
{
ITest<Animal> animalTest = new Test<Dog>(); //协变
}
}
在上面的代码中,我们定义了一个 Test 类,实现了 ITest 接口,并且使用了 out 关键字限定了 T 的类型。其中,IAnimal 是 Animal 的子类,也就是说,Dog 类型是 Animal 的子类。
在 Main() 方法中,我们使用 Test
逆变
逆变与协变正好相反,是指在保持类型安全的前提下,可以将能够接受泛型类对象的类型更改为可以接受泛型类的基类。也就是说,对于一个泛型类型 T
我们可以理解一个泛型类的逆变是这个泛型类泛型参数的类型可以隐式向下转换。例如:
public interface IAnimal { }
public class Animal { }
public class Dog : Animal, IAnimal { }
public interface ITest<in T> where T : Animal
{
void Post(T animal);
}
public class Test<T> : ITest<T> where T : Animal
{
public void Post(T animal)
{
//DO SOMETHING
}
}
public class Program
{
public static void Main(string[] args)
{
ITest<Dog> dogTest = new Test<Animal>(); //逆变
}
}
在上面的代码中,我们定义了一个 Test 类,实现了 ITest 接口,并且使用了 in 关键字限定了 T 的类型。其中,IAnimal 是 Animal 的子类,也就是说,Dog 类型是 Animal 的子类。
在 Main() 方法中,我们使用 Test
示例
协变示例:IEnumerable
IEnumerable
下面是一个利用协变的例子:
public static void Main(string[] args)
{
var dogs = new List<Dog>
{
new Dog(),
new Dog()
};
IEnumerable<IAnimal> animals = dogs;
}
在这个例子中,我们把 List
逆变示例:Func
Func
下面是一个利用逆变的例子:
public static void Main(string[] args)
{
Func<Animal, string> animalToString = animal => animal.ToString();
Func<Dog, string> dogToString = animalToString;
Console.WriteLine(dogToString(new Dog()));
}
在这个例子中,我们把一个 Func
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一文带你了解C#中的协变与逆变 - Python技术站