Why do I get a compile error in the following code (see line with comment)?
public void Test()
{
HashSet<HashSet<Animal>> setWithSets = new HashSet<HashSet<Animal>>();
HashSet<Cat> cats = new HashSet<Cat>();
setWithSets.Add(cats); // Compile error
}
private class Animal { }
private class Cat : Animal { }
VS2012 gives me two errors, the first one the important one:
My question is: Why can I not add "cats" to the "setWithSets"?
To better understand why this is not allowed, consider the following program.
The line setOfSets.First().Add(new Dog());
is acceptable to the compiler, because a collection of animals can surely hold an instance of Dog
. The problem is that the first collection of animals in the collection is a collection of Cat
instances, and Dog
does not extend Cat
.
class Animal { }
class Cat : Animal { }
class Dog : Animal { }
class Program {
static void Main(string[] args) {
// This is a collection of collections of animals.
HashSet<HashSet<Animal>> setOfSets = new HashSet<HashSet<Animal>>();
// Here, we add a collection of cats to that collection.
HashSet<Cat> cats = new HashSet<Cat>();
setOfSets.Add(cats);
// And here, we add a dog to the collection of cats. Sorry, kitty!
setOfSets.First().Add(new Dog());
}
}
Even if Cat
derives from Animal
, it is not true that HashSet<Cat>
derives from HashSet<Animal>
. (The only base class of HashSet<Anything>
is the object
class.)
To get the behavior you want, the HashSet<T>
generic type would need to be covariant in its type parameter T
. But it is not, for two reasons:
HashSet<>
is a class.HashSet<>
, you can also add to it (and do other things). Therefore covariance is logically impossible. Or else one would be able to regard a HashSet<Cat>
as a HashSet<Animal>
and then add a Dog
to it. But a set of cats does not allow dogs.If you changed HashSet<T>
into for example IReadOnlyCollection<T>
(see .NET 4.5 documentation: IReadOnlyCollection<out T>
Interface), things would work because the latter type (1) is an interface, (2) allows only reads, and (3) has therefore premitted a marking "I'm covariant in T
" which the authors of the type decided to apply.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With