Почему делает функцию, которая берет IEnumerable <интерфейс> не, принимают IEnumerable <класс>?

Скажите, например, у меня есть класс:

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. Причем приземленный реальный пример производящий список автомобилей, и затем будучи сказанным, что это не был список механизмов.

Это - только незначительное раздражение, но если бы кто-либо может пролить некоторый свет на это, я был бы очень обязан.

5
задан Mechanical snail 21 November 2012 в 07:02
поделиться

4 ответа

Это будет работать в C # 4.0! То, о чем вы говорите, называется общей ковариацией .

А пока вы можете использовать метод расширения Cast :

List<IMyBar> interfaceList = new List<IMyBar>(classList.Cast<IMyBar>());
14
ответ дан 18 December 2019 в 07:29
поделиться

Это поддерживается в .NET 4.0, но не ранее.

http://msdn.microsoft.com/en-us/library/dd799517%28VS.100%29.aspx

3
ответ дан 18 December 2019 в 07:29
поделиться

Чтобы уточнить, причина, по которой он сейчас не работает, заключается в том, что IEnumerable не наследуется от IEnumerable . Я повторю это еще раз: перечислимый объект производного типа не наследуется от перечислимого объекта базового типа. Скорее, оба типа специализируются на универсальном типе IEnumerable . В .Net 3.5 и ниже они не имеют других отношений, кроме специализации (которая не является наследованием), и в остальном являются двумя совершенно разными типами в системе типов.

.Net 4.0 вообще не изменит отношения между этими типами. Они по-прежнему будут двумя совершенно разными типами, которые связаны только через специализацию. Что он будет делать, так это позволять вам писать методы, которые знают об отношениях специализации, и в некоторых случаях позволяет вам заменять один, когда вы пишете другой.

3
ответ дан 18 December 2019 в 07:29
поделиться

Если вы хотите выполнять приведение между 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
1
ответ дан 18 December 2019 в 07:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: