РЕДАКТИРОВАТЬ: Я только что понял, что я действительно не ответил на аспект, как обойти ограничение. К счастью, это довольно просто:
UseFoos(myFoos.Cast<IEnumerable<Foo>>());
Этот код прекрасно компилируется (когда вы дали имя параметру UseFoos
) в C # 4, что вводит универсальную ковариацию и контравариантность для интерфейсов и делегатов.
В качестве более простого примера это работает в C # 4, но не в C # 3:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
Обратите внимание, что даже в C # 4 классы не являются инвариантами, поэтому это не будет работать:
// This won't work
List<string> strings = new List<string>();
List<object> objects = strings;
... и даже для интерфейсов, он поддерживается только тогда, когда это безопасно:
// This won't work either
IList<string> strings = new List<string>();
IList<object> objects = strings;
Интерфейс (или делегат) должен объявить дисперсию самого параметра типа, поэтому если вы посмотрите документацию .NET 4 для IEnumerable<T>
, вы увидите, что она объявлена как
public interface IEnumerable<out T>
где out
объявляет ковариацию в T
.
Эрик Липперт имеет лот подробнее об этом в своем блоге в категории ковариация и контравариантность .