Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I pass a List<List<Foo>> to an IEnumerable<IEnumerable<Foo>>

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?

like image 350
Dan Is Fiddling By Firelight Avatar asked Dec 21 '11 15:12

Dan Is Fiddling By Firelight


1 Answers

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.

like image 146
Jon Skeet Avatar answered Oct 21 '22 17:10

Jon Skeet