This code generates two compile time errors:
private void DoSomething()
{
List<List<Foo>> myFoos = GetFoos();
UseFoos(myFoos);
}
private void UseFoos(IEnumerable<IEnumerable<Foo>>)
{
}
The best overloaded method match for 'NameSpace.Class.UseFoos(System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable<Foo>>)' has some invalid arguments
and
Argument 1: cannot convert from 'System.Collections.Generic.List<System.Collections.Generic.List<Foo>>' to 'System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable<Foo>>'
Casting to IEnumberable<List<Foo>>
isn't a problem. What's different about casting the inner List
component of the type that it fails?
EDIT: I've just realized that I haven't really answered the aspect of how to work around the limitation. Fortunately it's quite easy:
UseFoos(myFoos.Cast<IEnumerable<Foo>>());
That code compiles fine (when you've given the UseFoos
parameter a name) under C# 4, which introduced generic covariance and contravariance for interfaces and delegates.
As a simpler example, this works in C# 4 but not in C# 3:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
Note that even in C# 4, classes aren't invariant, so this won't work:
// This won't work
List<string> strings = new List<string>();
List<object> objects = strings;
... and even for interfaces, it's only supported when it's safe:
// This won't work either
IList<string> strings = new List<string>();
IList<object> objects = strings;
The interface (or delegate) has to declare the variance of the type parameter itself, so if you look at the .NET 4 documentation for IEnumerable<T>
you'll see it's declared as
public interface IEnumerable<out T>
where out
declares the covariance in T
.
Eric Lippert has a lot more about this in his blog category of covariance and contravariance.
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