#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# и не пробует браться за неё. (За исключением нескольких простых случаев, да.)
Комментариев нет:
Отправить комментарий