.NET - 集合与继承

4
我有三个拥有相同父类的类。我们称之为Animal,其子类是Dog、Cat和Parrot。
我有一个可观察集合,其中包含用户正在使用的动物集合。集合包含所有相同类型的动物 - 用户只能使用所有狗、所有猫或所有鹦鹉中的一种。
所以我声明了ObservableCollection animals,并根据用户选择更改属性animals的内容为ObservableCollection或ObservableCollection或ObservableCollection。因此,无论用户当前使用狗还是猫,他都可以选择动物具有的所有共同操作。
但它不起作用。似乎我不能将ObservableCollection分配给类型为ObservableCollection的属性。我认为应该可以,因为动物是猫的超类型,所以我可以像往常一样将猫分配给动物变量。
为什么我不能这样做,如何解决这个问题呢?
4个回答

5

它不能正常工作的一个原因是:如果它能够正常工作,你就可能会遇到无意义的情况:

ObservableCollection<Animal> animals = new ObservableCollection<Dog>();
animals.Add(new Cat()); // cat is an animal, after all

另一个原因是,ObservableCollection<Dog> 并不是继承自 ObservableCollection<Animal> - 它们只是不同的(并行的)封闭泛型类型的 ObservableCollection<>
允许的是一些具有“仅输出”API的接口(如 IEnumerable<T>)可以是协变的,所以如果你只需要迭代它们,你可以有:
IEnumerable<Animal> animals = new ObservableCollection<Dog>();

(可能是将狗添加到其他地方)

另一种方法是使用非通用API:

IList animals = new ObservableCollection<Dog>();

1

不要使用 ObservableCollection,而是将这些集合类型定义为 IEnumerable<T>,因为 ObservableCollection 不支持类型协变。任何允许你添加元素的集合都不会支持这种继承类型。为了理解原因,请考虑以下假设代码(它不能编译)

List<object> myObjects = new List<string>();

你可能会认为这没问题,但是如果你接下来写了以下内容,看看会发生什么:

myObjects.Add(new Dog());

myObjects 被声明为对象列表,因此上述代码将编译通过,但在运行时会出现问题,因为在底层,myObjects 被实例化为仅容纳字符串。


没有常规集合类型支持协变;a: 不可能有一个具有Add机制和获取值的集合类型同时支持方差,b: 只有接口和委托支持4.0风格的方差,即:IEnumerable<out T>,但不包括类本身。 - Marc Gravell
我正在使用C# 4.0。我正在绑定到这个集合,所以我需要使用ObservableCollection。这可能吗? - user1018711
@Marc - 我知道这一切 - 你能告诉我我的回答哪一部分暗示了相反的意思,这样我就可以更清楚地表达吗? - Adam Rackis
1
那将是你的忍者编辑之前的部分,那时它不太明确;p - Marc Gravell
@Marc - 我想这已经成为历史了 :) -- 不过还是谢谢你提醒我。 - Adam Rackis

0
不需要协变的话,不要过度复杂化。无论你是用猫、狗还是鹦鹉填充它,你都应该创建一个ObservableCollection<Animal>,因为你没有使用任何子类功能。
你没有提到为什么使用ObervableCollection,但如果你不观察它并且不关心被通知列表更改,那么你可以将其转换。

0
将其变成一个接口,并使用协方差
interface ObservableCollection <out T>
{

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接