Когда так (как вы предлагаете) пытаются сделать, выглядит это как будто бы автор хочет сэкономить на наборе текста.
Структуре, возвращаемой из публичного GetEnumerator() никакой интерфейс не нужен. А из реализации IEnumerable::GetEnumerator() нужно наоборот, вернуть [ссылочный тип] интерфейс. Хоть реализация одна и та же, внешние требования разные. Если для вас это важно, уже из-за SRP следует разделить.
Подозреваю, что авторы стремились избавиться от боксинга. Зачем за него платить, если можно легко и просто скопипастить один раз немного кода и завернуть его в другую приватную обёртку?
J>Кста, а где реализация List<> , что то не могу найти ?
Здравствуйте, Jack128, Вы писали:
J>В реализации ImmutableQueue (хотя наверняка не только в нем)
Второй поддерживает IEnumerator (не генерик) + IDisposable + Reset(). Первый максимально дешёвый. MoveNext() даже инлайниться должен.
J>собственно вопрос: почему бы не оставить одну реализацию (struct) и в ней реализовать IEnumerator<> ?
На одно поле больше + не инлайнится из-за throw.
Здравствуйте, Sinix, Вы писали:
J>>собственно вопрос: почему бы не оставить одну реализацию (struct) и в ней реализовать IEnumerator<> ? S>На одно поле больше + не инлайнится из-за throw.
Так явно throw и во втором нет, там же просто вызов ThrowIfDisposed(); (как раз отчасти специально для инлайнинга так делают) поэтому и такой мувнекст может заинлайниться.
Другое дело — я не уверен, что косвенный вызов MoveNext() через интерфейс сможет заинлайниться.
S>>не инлайнится из-за throw.
X>Так явно throw и во втором нет, там же просто вызов ThrowIfDisposed();
Мдя, тут протормозил Не, можно конечно посчитать размер il-кода (вдруг там из-за пары лишних инструкций получается > 34 байт и ограничение по размеру срабатывает), но после вот этой багофичи и после свежих планов по инлайнингу (рассматривают вариант с machine learning) я зарёкся спорить на тему что инлайнится, что нет. Только проверять и только каждый конкретный случай в индивидуальном порядке. Текущее поведение не задокументировано, но можно глянуть тесты.
Короче, теперь я тоже присоединяюсь к "а фиг его знает".
X>Другое дело — я не уверен, что косвенный вызов MoveNex() через интерфейс сможет заинлайниться.
И не должен, структура вполне может реализовать интерфейс явно, а сама соответствовать enumerator pattern.
2all: Если кто отстал от обсуждения, то обсуждаем примерно вот это.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Jack128, Вы писали:
J>>В реализации ImmutableQueue (хотя наверняка не только в нем) S>Второй поддерживает IEnumerator (не генерик) + IDisposable + Reset(). Первый максимально дешёвый. MoveNext() даже инлайниться должен.
Ну вот возьмем например List<T>.Enumerator, и IEnumerator, и IDisposable, и Reset, все есть. Но структура.
J>>собственно вопрос: почему бы не оставить одну реализацию (struct) и в ней реализовать IEnumerator<> ? S>На одно поле больше + не инлайнится из-за throw.
Если сделать пустую реализацию IDisposable, то и поле не нужно. С инлайнингом тоже вроде разобрались.
Given the wide range of scenarios, targets, and the two distinct code bases, we propose to heavily rely on machine learning techniques for building and tuning the Profitability components of the inliners.
и далее по тексту.
Вообще, всю документашку в coreclr вполне можно пролистать. Никаких особых секретов там нет, сплошные нюансы. Зато процентов эдак 50 нигде до этого не озвучивалось.
Здравствуйте, xy012111, Вы писали:
J>>В реализации ImmutableQueue (хотя наверняка не только в нем) J>>есть 2 энумератора:
… J>>собственно вопрос: почему бы не оставить одну реализацию (struct) и в ней реализовать IEnumerator<> ?
X>Подозреваю, что авторы стремились избавиться от боксинга. …
/// <summary>
/// enumerator that implements <see cref="IEnumerator{T}"/> pattern (including <see cref="IDisposable"/>).
/// it is used by LINQ and foreach when Slice is accessed via <see cref="IEnumerable{T}"/>
/// it is reference type to avoid boxing when calling interface methods on stuctures
/// </summary>private class EnumeratorObject : IEnumerator<T>