下面是“C#中的协变与逆变小结”的完整攻略:
什么是协变和逆变
协变和逆变是C#中的两个概念,它们都涉及到了类型转换。简单来说:
- 协变:表示在类型转换过程中,类型参数可以“向上转”,也就是说如果T1是T2的子类型,那么
Func<T1>
可以转换为Func<T2>
。 - 逆变:表示在类型转换过程中,类型参数可以“向下转”,也就是说如果T1是T2的子类型,那么
Action<T2>
可以转换为Action<T1>
。
协变和逆变的应用场景
协变和逆变主要用于泛型接口和委托的定义。在实际应用中,它们可以帮助我们写出更灵活的代码。
协变的应用场景
协变主要应用于泛型接口的定义。例如,我们可以定义一个实现了IEnumerable
public interface IEnumerable<out T>
{
IEnumerator<T> GetEnumerator();
}
我们可以看到,IEnumerable接口中的类型参数T被用out
关键字修饰,表示这个类型是协变的。这个接口定义了一个GetEnumerator()方法,用于返回一个IEnumerator
由于IEnumerable
IEnumerable<Dog> dogs = new List<Dog>();
IEnumerable<Animal> animals = dogs;
这样做是安全的,因为Animal是Dog的基类,List
逆变的应用场景
逆变主要应用于委托的定义。我们可以为一个参数列表包含了一个委托类型,并定义它的参数类型为逆变。例如:
public delegate void Comparison<in T>(T x, T y);
这里的in
关键字表示参数类型是逆变的。此处定义的委托表示比较两个T类型的对象。
由于ComparisonComparison<Animal>
类型的变量赋值给一个Comparison<Dog>
类型的变量:
Comparison<Animal> animalSort = (a, b) => a.Name.CompareTo(b.Name);
Comparison<Dog> dogSort = animalSort;
这样做是安全的,因为比较Animal对象的lambda表达式同样可以用于比较Dog对象,所以将一个Comparison
两条示例
下面是两个协变和逆变的示例:
示例1:IEnumerable接口的协变
using System;
using System.Collections.Generic;
class Animal
{
public string Name { get; set; }
public Animal(string name) => Name = name;
}
class Dog : Animal
{
public Dog(string name) : base(name) { }
}
class Program
{
static void Main()
{
IEnumerable<Dog> dogs = new List<Dog> { new Dog("Tom"), new Dog("Jerry") };
IEnumerable<Animal> animals = dogs;
foreach (Animal animal in animals)
{
Console.WriteLine(animal.Name);
}
}
}
上面的代码中,我们定义了Animal和Dog两个类,其中Dog是Animal的子类。我们还定义了一个泛型列表,用于存储Dog对象。
接下来,我们将这个Dog列表赋值给一个Animal接口类型的变量,这是因为IEnumerable
最后,我们使用foreach循环遍历这个Animal列表,输出每个Animal对象的Name属性。
示例2:Comparison委托的逆变
using System;
using System.Collections.Generic;
class Animal
{
public string Name { get; set; }
public Animal(string name) => Name = name;
}
class Dog : Animal
{
public Dog(string name) : base(name) { }
}
class Program
{
static void Main()
{
List<Dog> dogs = new List<Dog> { new Dog("Tom"), new Dog("Jerry") };
Comparison<Animal> animalSort = (a, b) => a.Name.CompareTo(b.Name);
Comparison<Dog> dogSort = animalSort;
dogs.Sort(dogSort);
foreach (Dog dog in dogs)
{
Console.WriteLine(dog.Name);
}
}
}
上面的代码中,我们定义了Animal和Dog两个类,并且定义了一个Comparison
在Main函数中,我们使用List
注意,由于我们将一个比较Animal对象的lambda表达式赋给了一个比较Dog对象的变量,所以这个比较器对Dog对象的比较也是正确的。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#中的协变与逆变小结 - Python技术站