Скажите, например, у меня есть класс:
public class MyFoo : IMyBar
{
...
}
Затем я хотел бы использовать следующий код:
List<MyFoo> classList = new List<MyFoo>();
classList.Add(new MyFoo(1));
classList.Add(new MyFoo(2));
classList.Add(new MyFoo(3));
List<IMyBar> interfaceList = new List<IMyBar>(classList);
Но это производит ошибку:
`Argument '1': cannot convert from 'IEnumerable<MyFoo>' to 'IEnumerable<IMyBar>'
Почему это? Так как MyFoo реализует IMyBar, можно было бы ожидать, что IEnumerable MyFoo можно было рассматривать как IEnumerable IMyBar. Причем приземленный реальный пример производящий список автомобилей, и затем будучи сказанным, что это не был список механизмов.
Это - только незначительное раздражение, но если бы кто-либо может пролить некоторый свет на это, я был бы очень обязан.
Это будет работать в C # 4.0! То, о чем вы говорите, называется общей ковариацией .
А пока вы можете использовать метод расширения Cast
:
List<IMyBar> interfaceList = new List<IMyBar>(classList.Cast<IMyBar>());
Это поддерживается в .NET 4.0, но не ранее.
http://msdn.microsoft.com/en-us/library/dd799517%28VS.100%29.aspx
Чтобы уточнить, причина, по которой он сейчас не работает, заключается в том, что IEnumerable
не наследуется от IEnumerable
. Я повторю это еще раз: перечислимый объект производного типа не наследуется от перечислимого объекта базового типа. Скорее, оба типа специализируются на универсальном типе IEnumerable
. В .Net 3.5 и ниже они не имеют других отношений, кроме специализации (которая не является наследованием), и в остальном являются двумя совершенно разными типами в системе типов.
.Net 4.0 вообще не изменит отношения между этими типами. Они по-прежнему будут двумя совершенно разными типами, которые связаны только через специализацию. Что он будет делать, так это позволять вам писать методы, которые знают об отношениях специализации, и в некоторых случаях позволяет вам заменять один, когда вы пишете другой.
Если вы хотите выполнять приведение между IEnumerables (как вы написали в заголовке своего вопроса), а не между списками (как вы написали в своем вопросе), вы можете подождите, пока появится функция ковариации С # 4.0. До этого дня вы можете использовать методы расширения. Но я бы не стал использовать метод расширения Cast , указанный в других ответах, но написал свой собственный метод, который можно использовать только для ковариационного приведения в IEnumerable. Когда / если вы переключитесь на C # 4.0, вы легко найдете все места в вашем коде, где приведение будет избыточным.
public static class cEnumerableExtensions
{
public static IEnumerable<TResult> CovarianceConversion<TResult, TSource>(this IEnumerable<TSource> source)
where TSource : TResult
{
foreach (var item in source)
{
yield return item;
}
}
}
Последний узел. Кажется, не существует константы прекомпилятора для netframework 4.0 , иначе я бы добавил
#if DOTNET4
[Obsolete("You can directly cast in C# 4.0.")]
#endif