.NET - Коллекции и наследство - PullRequest
4 голосов
/ 12 декабря 2011

У меня есть три класса с общим родителем.Допустим, родитель - это животное, а дети - собака, кошка и попугай.

И у меня есть одна наблюдаемая коллекция, которая содержит коллекцию животных, с которыми работает пользователь.Коллекция содержит всех животных одного типа - пользователь работает либо со всеми собаками, либо со всеми кошками, либо со всеми попугаями.

Итак, я объявил ObservableCollection<Animal> животных и, в зависимости от выбора пользователя, хочу изменить содержимое свойства животных наObservableCollection<Dog> или ObservableCollection<Cat> или ObservableCollection<PArrot>.Поэтому не имеет значения, работает ли пользователь в настоящее время с собаками или кошками, но он может выбрать все общие действия животных.

Но это не работает.Кажется, я не могу присвоить ObservableCollection<Cat> свойству типа ObservableCollection<animal>.Я бы подумал, что это должно сработать, потому что animal это супертип cat, поэтому я могу назначить cat для переменной животного как обычно.

Почему я не могу это сделать и как я могу решить эту проблему?

Ответы [ 4 ]

5 голосов
/ 12 декабря 2011

Одна из причин, по которой он не работает: если он сработал , у вас может возникнуть бессмысленный сценарий:

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

Другая причина в том, что это просто не тот случай, когда ObservableCollection<Dog> наследует ObservableCollection<Animal> - это просто разные (параллельные) закрытые универсальные типы ObservableCollection<>.

Что разрешено , так это то, что некоторые интерфейсы с "out"только «API» (такие как IEnumerable<T>) могут быть ковариантными , поэтому, если вам нужно только итерировать их, вы можете иметь:

IEnumerable<Animal> animals = new ObservableCollection<Dog>();

(предположительно добавление собак где-то еще)

Другой подход заключается в использовании неуниверсального API:

IList animals = new ObservableCollection<Dog>();
1 голос
/ 12 декабря 2011

Вместо использования ObservableCollection вам придется печатать эти коллекции как IEnumerable<T>, так как ObservableCollection не поддерживает ковариацию типов. Ни одна коллекция, которая позволяет вам добавлять элементы, никогда не будет поддерживать этот тип наследования. Чтобы понять почему, рассмотрим этот гипотетический код (который не компилируется)

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

Вы могли бы подумать, что это будет хорошо, но посмотрите, что произойдет, если вы тогда напишите следующее:

myObjects.Add(new Dog());

myObjects объявлен как список объектов, поэтому приведенный выше код будет компилироваться, но во время выполнения все может взорваться, поскольку под прикрытием создается экземпляр myObjects, содержащий только строки.

0 голосов
/ 12 декабря 2011

Не усложняйте его ковариацией, если вам это не нужно. Вы должны создать ObservableCollection<Animal> независимо от того, заполняете ли вы его кошками, собаками или попугаями, так как вы не используете какую-либо подклассовую функциональность.

Вы не упомянули, почему вы используете ObervableCollection, но если вы не соблюдаете его и не заботитесь о том, чтобы получать уведомления об изменениях в списке, вы можете также преобразовать его.

0 голосов
/ 12 декабря 2011

Создайте интерфейс и используйте ко-дисперсию

interface ObservableCollection <out T>
{

}
...