2016-07-29 2 views
-1

Просто попробуйте некоторые основы с C# Lookup collection и обнаружите, что этот простой пример компилируется отлично, даже Интерфейс IGrouping должен иметь . Элемент установлен как int.Почему я не получаю синтаксическую ошибку в этом примере кода?

string txt = "Hello world!"; 
ILookup<char, int> occurrences = Enumerable.Range(0, txt.Length).ToLookup(i => txt[i], i => i); 

foreach (IGrouping<char, string> values in occurrences) 
    Console.WriteLine($"{values.Key}: {string.Join(", ", values)}"); 

Очевидно, что я получаю ошибку во время выполнения при недействительном литье. Но я ожидал, что это работа для компилятора ...

+0

@PeterDuniho: Мы можем согласиться на [этот вопрос и эти ответы] (http://stackoverflow.com/a/20205068/717732)? Это буквальный. Да, хотя ** название ** нечетно, вопрос и семантика/смысл/.. совпадают. – quetzalcoatl

+0

@Quetzalcoatl: намного лучше, да ... это похоже на этот вопрос. Я думаю, что Скотт немного подошел к сорнякам ближе к концу своего ответа с делом о ковариации, но в остальном это разумное факсимиле этого Q & A. –

ответ

1

Кажется, здесь есть правило, которое использует компилятор:

Если компилятор может видеть, что тип значения или запечатанный класс не реализовать или наследовать тип, который программист пытается передать в/из, литье является незаконным во время компиляции.

(Благодаря Jeppe Стиг Nielsen за упоминание этого в комментариях.)

Вот результат компиляции foreach (XXXX values in occurrences), если вы используете одну из следующих вариантов вместо XXXX в вашем примере. Обратите внимание: occurrences имеет тип ILookup<char, int>, который получен из IGrouping<char, int>.

  • public class MyClass { } компилирует
  • public sealed class MyClass { } время компиляции Ошибка
  • public sealed class MyClass : IGrouping<char, int> {...} Собирает
  • public sealed class MyClass : IGrouping<char, string> {...} ошибка времени компиляции
  • public struct MyStruct {} ошибка времени компиляции
  • public struct MyStruct : IGrouping<char, string> {...} ошибка времени компиляции
  • public struct MyStruct : IGrouping<char, int> {...} Компилирует

Вот хороший блог post по Кшиштоф Квалина, который описывает, как утка, набрав в используемом в Еогеаспе:

Еогеаспа оператора C#»s уже использует утку печатать. Это может быть удивительно для некоторых, но для поддержки foreach в C# вам не нужно реализовывать IEnumerable! Все, что вам нужно сделать, это:

Обеспечить публичный метод GetEnumerator, который не принимает никаких параметров и возвращает тип, который имеет два элемента: а) метод MoveMext, который не принимает никаких параметров и возвращает логическое значение, и б) недвижимости Current с получатель, который возвращает объект.

+0

Причина, по которой не может быть ошибки времени компиляции, заключается в том, что мы используем интерфейсы. Компилятор знает, что у него есть «IGrouping » (из типа свойства Current), но любой класс реализует это, в принципе может реализовать «IGrouping ». Любой может написать класс, который реализует оба из них.Поскольку компилятор не может исключить, что фактические элементы, предоставленные, все такие, это разрешено. Моя рекомендация - использовать 'var' во всех операциях foreach. –

+0

@JeppeStigNielsen: _ "в принципе может реализовать IGrouping ." _ - но если вызванный метод 'GetEnumerator()' не перечисляет этот интерфейс, это не поможет. Совместимость интерфейса - полная красная селедка. _ «Поскольку компилятор не может исключить ...» _ - но, опять же ... только потому, что это был конкретный выбор разработчиков для оператора 'foreach'. Когда были введены дженерики, спецификация могла бы измениться, чтобы требовать прямой совместимости типов вместо использования утиного ввода (не отбрасывая ожидаемый интерфейс, поскольку ваш комментарий подразумевает ... снова, красно-селедка). –

+0

@JeppeStigNielsen: _ «Моя рекомендация - использовать var во всех операциях foreach.» _ - ugh, действительно? Это полностью отрицало бы полезность даже совместимости типов с помощью утиного ввода, так как тогда вам приходилось писать явные приведения в любое время, когда тип коллекции точно не соответствует вашему желаемому типу переменной цикла. –

Смежные вопросы