Search code examples
c#genericscovariance

What is the point behind this covariance related code?


I have been reading a book named c# 7.0 in a Nutshell by O'REILLY, Topic: Variance is not Automatic. There is an example with 2 classes, Animal and Bear in which Animal>Bear:

public class Animal { }
public class Bear: Animal { }

And also there is a class like this:

public class Stack<T>
{
    private int position;
    T[] data = new T[100];
    public void Push(T obj) => data[position++] = obj;
    public T Pop() => data[--position];
}

In continue there are 2 versions of same class:

public class ZooCleaner1
{
    public static void Wash(Stack<Animal> animals) { }
}

and:

public class ZooCleaner2
{
    public static void Wash<T>(Stack<T> animals) where T: Animal { }
}

It explains that if I try to write:

ZooCleaner1.Wash(bears);
ZooCleaner2.Wash(bears);

the first line gets a compile-time error which says that it is not able to convert Bear to Animal. But the second line is correct and works fine. As I am new to this topc, I can't Understand the diffrence betwean these 2 lines and I think they both accept Stack<Animal> and why do we need to use conditional generics?


Solution

  • Stack<Animal> represents a stack of objects of any Animal type. Stack<T> where T: Animal represents a stack of a single type so long as that type inherits from Animal.

    You cannot use a Stack<Bear> in place of a parameter declared as Stack<Animal> becuse, if you could, then the method could push a Fish onto the stack of bears. When the method that is using the stack of Bears pops it off of the stack, imagine the surprise when it pops off a fish!

    The second method, on the other hand, is generic, meaning that it can accept a stack of any type, so long as that type inherits from Animal So if the method gets a Stack<Bear>, it can only push another Bear onto the stack. Trying to push a Fish would be a runtime error.