do I just completely misunderstand contravariance?
Yes. You have completely and totally misunderstood what "covariance" and "contravariance" mean. You have confused them with assignment compatibility.
This is an extremely common error. The two concepts are related, but they are not at all the same.
Assignment compatibility is the property that an expression of one type may be stored in a variable of another type.
Covariance is the property that a mapping from types to types preserves the direction assignment compatibility. If Giraffe is assignment compatible with Animal, and this implies that IEnumerable<Giraffe>
is assignment compatible with IEnumerable<Animal>
then the IEnumerable<T>
mapping is covariant.
See my article on the subject for more details:
http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx
Setting a to B works, which is covariance
Yes it works. "a" is assignment compatible with B. It is not "covariance" because nothing is varying. There is no mapping from types to types that preserves the direction of assignment compatibility used in the assignment "a = B"; nothing is even generic.
but setting b to a new A fails with a compile error.
Correct.
Is there a way to do this ?
No. Instead of "A" and "B", call them Animal and Giraffe. Every Giraffe is an Animal, so if a variable can hold an Animal, then it can hold a Giraffe. If you try to go the other way, you can't put an Animal into a variable of type Giraffe. The Animal might actually be a Tiger. Why should you be allowed to put a Tiger into a variable of type Giraffe?