Страницы

Поиск по вопросам

среда, 12 февраля 2020 г.

Можно ли IEnumerator<T> привести к IEnumerable<T>?

#c_sharp


Объясните,пожалуйста,почему в ниже приведенном коде возможен Upcast типа IEnumerator
к типу IEnumerable,ведь IEnumerator не наследуется от IEnumerable



static IEnumerator GetOddNumbers(params int[] numbers)
{
    foreach (var number in numbers)
    {
        if (number % 2 != 0) yield return number;
    }
}

static void Main(string[] args)
{

    IEnumerable enumerable = (IEnumerable)GetOddNumbers(1, 2, 3);
    IEnumerator enumerator = GetOddNumbers(1, 2, 3);



    //List oddnumbers = new List(GetOddNumbers(1, 2, 3));

    //foreach (var number in oddnumbers)
    //{
    //    Console.WriteLine(number);
    //}

    //Console.ReadLine();
}

    


Ответы

Ответ 1



Извините, неверно прочитал вопрос вначале, ответ полностью переписан. Дело в том, что в C# любой объект можно закастить к любому интерфейсу на этапе компиляции: interface I1 { } class Program { static void Main(string[] args) { I1 i1 = (I1)(new Program()); } } В рантайме, если объект реально не имплементирует интерфейс, выбросится исключение InvalidCastExcetion. Почему же разрешён каст к интерфейсу, хотя объект на самом деле не имплементирует этот интерфейс? Рассмотрим код Program p = new Program(); I1 i1 = (I1)p; В этой точке статический тип выражения p, на которое навешен каст — Program. Но реальный, динамический тип может быть любой, производный от Program. И этот тип вполне может имплементировать интерфейс! Поэтому компилятор не может доказать, что каст невозможен, и откладывает проверку до момента реального выполнения. Сравните: interface I1 { } sealed class Program // добавили sealed { static void Main(string[] args) { I1 i1 = (I1)(new Program()); // Не компилируется, ошибка CS0030 } } В этих условиях компилятор таки может доказать, что выражение не может имплементировать интерфейс, ведь класс Program этот интерфейс не имплементирует, а производных классов быть не может. Вот этот код и не компилируется. Компилятор, конечно, мог бы быть суперумным, и увидеть, что выражение GetOddNumbers(...) есть вызов функции-генератора, и не имплементирует IEnumerable. Но при этом он должен был бы решать это не по декларируемому типу (IEnumerator), а анализируя поток выполнения программы. Это в общем случае неразрешимая задача, так что компилятор C# и не пробует браться за неё. (За исключением нескольких простых случаев, да.)

Комментариев нет:

Отправить комментарий