Безопасная проверка неповторяющихся IEnumerables на пустоту

Бывают случаи, когда полезно проверить неповторяемый IEnumerable, чтобы узнать, пуст ли он. LINQ Any не очень хорошо подходит для этого, поскольку он потребляет первый элемент последовательности, например

if(input.Any())
{
    foreach(int i in input)
    {
        // Will miss the first element for non-repeatable sequences!
    }
}

(Примечание: я знаю, что в этом случае нет необходимости выполнять проверку - это просто пример! Реальный пример - это выполнение Zip против правой части IEnumerable, которая потенциально может быть пустой. Если он пуст, я хочу, чтобы результатом был левый IEnumerable как есть.)

Я придумал потенциальное решение, которое выглядит так:

private static IEnumerable<T> NullifyIfEmptyHelper<T>(IEnumerator<T> e)
{
    using(e)
    {
        do
        {
            yield return e.Current;
        } while (e.MoveNext());
    }
}

public static IEnumerable<T> NullifyIfEmpty<T>(this IEnumerable<T> source)
{
    IEnumerator<T> e = source.GetEnumerator();
    if(e.MoveNext())
    {
        return NullifyIfEmptyHelper(e);
    }
    else
    {
        e.Dispose();
        return null;
    }
}

Это можно использовать следующим образом:

input = input.NullifyIfEmpty();
if(input != null)
{
    foreach(int i in input)
    {
        // Will include the first element.
    }
}

У меня два вопроса по этому поводу:

1) Разумно ли это делать? Может ли это быть проблематичным с точки зрения производительности? (Я думаю, что нет, но спросить стоит)

2) Есть ли лучший способ достижения той же конечной цели?


EDIT #1:

Вот пример неповторяющегося IEnumerable, чтобы прояснить:

private static IEnumerable<int> ReadNumbers()
{
    for(;;)
    {
        int i;
        if (int.TryParse(Console.ReadLine(), out i) && i != -1)
        {
            yield return i;
        }
        else
        {
            yield break;
        }
    }
}

В основном, вещи, которые поступают из пользовательского ввода или потока, и т.д.

EDIT #2:

Мне нужно уточнить, что я ищу решение, которое сохраняет ленивую природу IEnumerable - преобразование его в список или массив может быть решением в определенных обстоятельствах, но это не то, что я ищу здесь. (Реальная причина в том, что количество элементов в IEnumerable в моем случае может быть огромным, и важно не хранить их все в памяти сразу.)

13
задан Stuart Golodetz 9 February 2012 в 01:41
поделиться