C #: IEnumerator <T>в операторе использования - PullRequest
6 голосов
/ 02 июня 2009

Мне было любопытно посмотреть, как метод SingleOrFallback был реализован в MoreLinq , и обнаружил то, чего раньше не видел:

    public static T SingleOrFallback<T>(this IEnumerable<T> source, Func<T> fallback)
    {
        source.ThrowIfNull("source");
        fallback.ThrowIfNull("fallback");
        using (IEnumerator<T> iterator = source.GetEnumerator())
        {
            if (!iterator.MoveNext())
            {
                return fallback();
            }
            T first = iterator.Current;
            if (iterator.MoveNext())
            {
                throw new InvalidOperationException();
            }
            return first;
        }
    }

Почему IEnumerator<T> в операторе using? Об этом следует подумать при использовании foreach на IEnumerable<T> также?

Дополнительный вопрос: Что именно делает этот метод? Возвращает ли он запасной элемент всякий раз, когда исходная последовательность не содержит ровно один элемент?

Ответы [ 2 ]

11 голосов
/ 02 июня 2009

IEnumerator<T> extends IDisposable, так что у вас должно быть в выражении использования. foreach делает это автоматически. (Неуниверсальный IEnumerator не расширяет IDisposable, но компилятор C # все еще генерирует код для условного вызова Dispose. Это было одно из (немногих) изменений между C # 1.0 и 1.2, где 1.2 - это версия, поставляемая с .NET 1.1, по некоторым причинам.)

Вот статья , объясняющая, почему это важно в контексте блоков итераторов.

Что касается метода:

  • Если последовательность пуста, вернуть запасной элемент
  • Если в последовательности ровно один элемент, вернуть его
  • Если в последовательности более одного элемента, выдается исключение

PS: Приятно видеть, что MoreLinq привлекает к себе внимание:)

0 голосов
/ 03 апреля 2011

Некоторые перечислители будут вести себя плохо, если Dispose не вызывается; для неуниверсальных это так же верно, как и для общих (неуниверсальные требуют, чтобы код либо утки набрал вызов Dispose, либо приведение к IDisposable, а затем вызвал IDisposable.Dispose). Хорошо по привычке обеспечивать удаление объектов IEnumerator; Я считаю, что это необходимо для правильности любой процедуры, которая принимает IEnumerable неизвестного типа.

...