早在 2009 年,Eric 就曾戏弄我们说 C# 4 会发生变化。那么我们今天的立场是什么?
我的答案中使用的类可以在底部找到。为了更容易理解,我们将使用 Mammal 类作为“父”类,将 Cat 和 Dog 类用作“子类”。猫和狗都是哺乳动物,但猫不是狗,狗不是猫。
这仍然不合法,也不可能:
List<Cat> cats = new List<Cat>();
List<Mammal> mammals = cats;
为什么不呢?猫是哺乳动物,为什么我们不能将猫的列表分配给List<Mammal>?
因为,如果允许我们在 List<Mammal> 变量中存储对 List<Cat> 的引用,我们就可以编译以下代码以将狗添加到猫列表中:
mammals.Add(new Dog());
我们不能允许这样!请记住,mammals 只是对cats 的引用。 Dog 不是 Cat 的后代,并且在 Cat 对象列表中没有任何业务。
Starting with .NET Framework 4,几个泛型接口具有使用 C# 4 中引入的out 泛型修饰符关键字声明的协变类型参数。这些接口中有IEnumerable<T>,它当然是由List<T> 实现的。
这意味着我们现在可以将List<Cat> 转换为IEnumerable<Mammal>:
IEnumerable<Mammal> mammalsEnumerable = cats;
我们无法向mammalsEnumerable 添加新的Dog,因为IEnumerable<out T> 是“只读”接口,即它没有Add() 方法,但我们现在可以使用cats 可以使用 IEnumerable<Mammal> 的任何地方。例如,我们可以将mammalsEnumerable 与List<Dog> 连接以返回一个新序列:
void Main()
{
List<Cat> cats = new List<Cat> { new Cat() };
IEnumerable<Mammal> mammalsEnumerable =
AddDogs(cats); // AddDogs() takes an IEnumerable<Mammal>
Console.WriteLine(mammalsEnumerable.Count()); // Output: 3. One cat, two dogs.
}
public IEnumerable<Mammal> AddDogs(IEnumerable<Mammal> parentSequence)
{
List<Dog> dogs = new List<Dog> { new Dog(), new Dog() };
return parentSequence.Concat(dogs);
}
类定义:
public abstract class Mammal { }
public class Cat: Mammal { }
public class Dog : Mammal { }