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?
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 Bear
s 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.