Starting back in 2007 I read a series on Co/contra-variance in C# by Eric Lippert â Eric is on the compiler team at MS and one of my favorite bloggers to read I might add. At the time, I remember myself reading along with the words but my eyes completely glazing over. To be honest the concept mostly eluded me at the time, so I wanted to take this opportunity to describe the feature in a way that made the most sense to me.
Ask yourself the following questions:
As youâll see below, the answers to these questions depends entirely on the version of the C# compiler you are using.
Naturally, the best way to answer the questions above is to turn them into a test. Letâs run them in 2008 and 2010 and check the results.
Â
In VS 2008 both tests failed. It turns out that T is T and not anything that is a superclass or subclass of T. The implications of this are that if you have a method that accepted an IEnumerable<Person>, but you have a List<SalesPerson>, you would think that you could surely pass your list into the method⌠unfortunately you would be incorrect.
In VS 2010 however, one of our tests actually passed. It turns out that in C# 3 a List<string> is in fact an IEnumerable<object>. So our simple scenario above would in fact allow us to pass a List<SalesPerson> to a method that accepts an IEnumerable<Person>.
The short explanation of this change is due to the fact that the IEnumerable<T> interface was actually changed in .NET 4 to be IEnumerable<out T> â a whole new reason to use the out keyword. This means that any method within this interface that uses the T parameter CAN ONLY RETURN T and never accept it into any method arguments. Other .NET 4 interfaces, such as IComparer<in T> are similar but opposite: any methods in this interface can only use T as a method input parameter but never the return type.
Ah so you noticed that one of our tests still failed even in VS 2010⌠Well if you read the recap above this will start to make sense. The List<T> class contains methods that use the T parameter as both inputs and outputs â it can insert T into the list and also retrieve an instance of T.
It would have to be declared as List<in out T> â which is not possible for two reasons:
Hopefully this quick introduction to generic variance was helpful. I am by no means an expert on this subject, so I encourage you to read Eric Lippertâs series above if this is something you find interesting!
Â
Leave a Comment