I didn't attend PDC 2008, but I heard some news that C# 4.0 is announced to support Generic covariance and contra-variance. That is, List<string>
can be assigned to List<object>
. How could that be?
In Jon Skeet's book C# in Depth, it is explained why C# generics doesn't support covariance and contra-variance. It is mainly for writing secure code. Now, C# 4.0 changed to support them. Would it bring chaos?
Anybody know the details about C# 4.0 can give some explanation?
A generic type is a generic class or interface that is parameterized over types.
In C#, covariance and contravariance enable implicit reference conversion for array types, delegate types, and generic type arguments. Covariance preserves assignment compatibility and contravariance reverses it.
Covariance can be translated as "different in the same direction," or with-different, whereas contravariance means "different in the opposite direction," or against-different. Covariant and contravariant types are not the same, but there is a correlation between them. The names imply the direction of the correlation.
You can declare a generic type parameter contravariant by using the in keyword. The contravariant type can be used only as a type of method arguments and not as a return type of interface methods. The contravariant type can also be used for generic constraints.
Variance will only be supported in a safe way - in fact, using the abilities that the CLR already has. So the examples I give in the book of trying to use a List<Banana>
as a List<Fruit>
(or whatever it was) still won't work - but a few other scenarios will.
Firstly, it will only be supported for interfaces and delegates.
Secondly, it requires the author of the interface/delegate to decorate the type parameters as in
(for contravariance) or out
(for covariance). The most obvious example is IEnumerable<T>
which only ever lets you take values "out" of it - it doesn't let you add new ones. That will become IEnumerable<out T>
. That doesn't hurt type safety at all, but lets you return an IEnumerable<string>
from a method declared to return IEnumerable<object>
for instance.
Contravariance is harder to give concrete examples for using interfaces, but it's easy with a delegate. Consider Action<T>
- that just represents a method which takes a T
parameter. It would be nice to be able to convert seamlessly use an Action<object>
as an Action<string>
- any method which takes an object
parameter is going to be fine when it's presented with a string
instead. Of course, C# 2 already has covariance and contravariance of delegates to some extent, but via an actual conversion from one delegate type to another (creating a new instance) - see P141-144 for examples. C# 4 will make this more generic, and (I believe) will avoid creating a new instance for the conversion. (It'll be a reference conversion instead.)
Hope this clears it up a bit - please let me know if it doesn't make sense!
Not that Jon hasn't already covered it, but here are some links to blogs and videos from Eric Lippert. He does a nice job of explaining it with examples.
https://blogs.msdn.microsoft.com/ericlippert/2007/10/16/covariance-and-contravariance-in-c-part-one/
The videos:
https://www.youtube.com/watch?v=3MQDrKbzvqU
https://www.youtube.com/watch?v=XRIadQaBYlI
https://www.youtube.com/watch?v=St9d2EDZfrg
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