.NET - Collections and Inheritance

I have three classes with a common parent. Let say that the parent is Animal, and the children - Dog, Cat and Parrot.

And I have one observable collection containing a collection of animals that the user is working with. The collection contains all animals of the same type - the user only works with all dogs or cats or all parrots.

So, I declared the animals ObservableCollection<Animal> , and depending on the user’s choice, I want to change the contents of the animal properties to ObservableCollection<Dog> or ObservableCollection<Cat> or ObservableCollection<PArrot> . Therefore, it does not matter if the user is currently working with dogs or cats, but he can choose all the actions that animals have together.

But that will not work. It seems that I cannot assign an ObservableCollection<Cat> Property of type ObservableCollection<Animal> . I think this should work because the animal is a supertype of the cat, so I can assign the cat a variable to the animal, as usual.

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

+4
source share
4 answers

One of the reasons this will not work: if it did , you might have a pointless scenario:

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

Another reason is that ObservableCollection<Dog> inherits ObservableCollection<Animal> - these are just different (parallel) private generic types of ObservableCollection<> .

What is allowed is that some APIs from just only (like IEnumerable<T> ) can be covariant, so if all you need to do is repeat them, you can have:

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

(presumably adding dogs elsewhere)

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

 IList animals = new ObservableCollection<Dog>(); 
+5
source

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

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

You would think that this would be normal, but see what happens if you then write the following:

 myObjects.Add(new Dog()); 

myObjects declared as a list of objects, so the above code will be compiled, but at runtime things will explode, since under the covers myObjects is created only to store strings.

+1
source

Make it an interface and use co-dispersion

 interface ObservableCollection <out T> { } 
0
source

Do not overwork it with covariance if you do not need it. You must create an ObservableCollection<Animal> regardless of whether you fill it with Cats, Dogs or Parrots, since you are not using any subclasses.

You did not indicate why you are using ObervableCollection, but if you do not observe it and do not care to be notified of changes in the list, you can also convert it.

0
source

Source: https://habr.com/ru/post/1385793/


All Articles