简体   繁体   中英

.NET - Collections and inheritance

I have three classes with common parent. Let's say parent is Animal and children are Dog,Cat and Parrot.

And I have one observable collection which contains collection of animals user is working with. Collection contains all animals of same type - user is either working only with all dogs or all cats or all parrots.

So I declared ObservableCollection<Animal> animals and depending on user choices I want to change contents of property animals to ObservableCollection<Dog> or ObservableCollection<Cat> or ObservableCollection<PArrot> . So it doesn't matter if user currently works with dogs or cats but he can choose all actions animals have in common.

But it doesn't work. It seems that I can't assign ObservableCollection<Cat> to Property of type ObservableCollection<animal> . I would think it should work, because animal is supertype of cat, so I can assign cat to animal variable as usual.

Why can't I do this and how can I solve this problem?

One reason it doesn't work: if it did work, you could have the nonsense scenario:

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

Another reason is that it is simply not the case that ObservableCollection<Dog> inherits ObservableCollection<Animal> - they are just different (parallel) closed generic types of ObservableCollection<> .

What is permitted is that some interfaces with "out only" APIs (such as IEnumerable<T> ) can be covariant , so if all you need is to iterate them, you can have:

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

(presumably adding the dogs somewhere else)

Another approach would be to use a non-generic API:

IList animals = new ObservableCollection<Dog>();

Instead of using ObservableCollection , you'll have to type these collections as IEnumerable<T> , since ObservableCollection does not support type covariance. No collection that allows you to add elements will ever support this type of inheritance. To see why, consider this hypothetical code (which does not compile)

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

You'd think this would be ok, but then look what would happen if you then wrote the following:

myObjects.Add(new Dog());

myObjects is declared as a List of objects, so the above code would compile, but at runtime things would blow up since, under the covers, myObjects is instantiated to only hold strings.

Make it an interface, and use co-variance

interface ObservableCollection <out T>
{

}

Dont over-complicate it with covariance if you dont need to. You should create ObservableCollection<Animal> irregardless of whether you are filling it with Cats, Dogs or Parrots since you don't use any subclassed functionality.

You have not mentioned why you use ObervableCollection, but if you don't observe it and do not care about being notified of changes to the list you might as well transform it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM