Утка набрав в компиляторе C#



Примечание это не вопрос о том, как реализовать или эмулировать ввод утки в C#...



в течение нескольких лет у меня было впечатление, что некоторые функции языка C# были depdendent на структурах данных, определенных в самом языке (который всегда казался мне странным сценарием курицы и яйца). Например, у меня сложилось впечатление, что foreach цикл был доступен только для использования с типами, которые реализованы IEnumerable.



С тех пор я понял, что компилятор C# использует duck typing, чтобы определить, можно ли использовать объект в цикле foreach, ища GetEnumerator метод, а не IEnumerable. Это имеет большой смысл, поскольку он удаляет загадку курицы и яйца.



Я немного смущен, почему это не похоже на случай с using блок а IDisposable. Есть ли какая-то особая причина, по которой компилятор не может использовать duck typing & look for a Dispose метод? В чем причина такого несоответствия?



возможно, что-то еще происходит под капотом с IDisposable?



обсуждая, почему вы бы когда-нибудь наличие объекта с методом Dispose, который не реализовал IDisposable, выходит за рамки этого вопроса :)

606   3  

3 ответов:

в этом нет ничего особенного IDisposable здесь - но там и что-то особенное про итераторы.

перед C# 2, используя этот тип утки на foreach был только вы могли бы реализовать строго типизированный итератор, а также единственный способ итерации по типам значений без бокса. Я подозреваемый что если бы C# и .NET имели дженерики для начала,foreach бы требуютсяIEnumerable<T> вместо этого и не было утиной типизацией.

теперь компилятор использует такой тип утки в нескольких других местах, которые я могу придумать:

  • инициализаторы коллекции ищут подходящий Add перегрузка (а также тип, который нужно реализовать IEnumerable, просто чтобы показать, что это действительно какая-то коллекция); это позволяет гибко добавлять отдельные элементы, пары ключ/значение и т. д.
  • LINQ (Select etc) - это как LINQ достигает своей гибкости, позволяющ этим же формат выражения запроса для нескольких типов, без необходимости изменять
  • выражения ожидания C# 5 требуют GetAwaiter чтобы вернуть тип ожидающего, который имеет IsCompleted/OnCompleted/GetResult

в обоих случаях это упрощает добавление функции к существующим типам и интерфейсам, где концепция ранее не существовала.

учитывая, что IDisposable в рамках с самой первой версии, я не думаю, что есть было бы какое-то преимущество в утке набрав using заявление. Я знаю, что вы явно пытались дисконтировать причины наличия Dispose без реализации IDisposable из обсуждения, но я думаю, что это решающий момент. Там должны быть веские причины для реализации функции в языке, и я бы сказал, что утка типизация является функцией выше и за пределами поддержки известного интерфейса. Если нет явной выгоды в этом, это не будет в конечном итоге на языке.

нет курицы и яйца: foreach зависит от IEnumerable С IEnumerable не зависит от foreach. Причина foreach разрешена для коллекций, не реализующих IEnumerable наверное во многом исторический:

в C#, это не является строго необходимым для наследования класса коллекции IEnumerable и IEnumerator по порядку чтобы быть совместимым с foreach; как долго как класс имеет необходимые GetEnumerator, MoveNext, Reset и Текущие члены, он будет работать с инструкция foreach. Опуская интерфейсы имеет преимущество позволять вам к определите тип возврата тока в будьте более конкретны, чем объект, тем самым обеспечение безопасности типов.

кроме того, не все проблемы с курицей и яйцом на самом деле являются проблемами: например, функция может вызвать себя (рекурсия!) или ссылочный тип может содержать себя (например, связанный список).

когда using пришел вокруг почему они используют что-то как сложно указать, как утка набрав, когда они могут просто сказать: реализовать IDisposable? В принципе, используя duck typing, вы выполняете конечный запуск вокруг системы типов, что полезно только тогда, когда система типов недостаточна (или непрактична) для решения проблемы.

вопрос, который вы задаете, не является ситуацией с курицей и яйцом. Его больше похоже на то, как реализован компилятор языка. Как C# и VB.NET компиляторы реализуются по-разному.Если вы напишете простой код hello world и скомпилируете его с помощью компилятора и проверите код IL, они будут разными. Возвращаясь к вашему вопросу, я хотел бы объяснить, какой код IL генерируется компилятором C# для IEnumerable.

IEnumerator e = arr.GetEnumerator();

while(e.MoveNext())
{
   e.Currrent;
}

таким образом, компилятор C# настраивается для этого случая из foreach.

Comments

    Ничего не найдено.