Даже проверки "IsNullOrEmpty" дают предупреждения "Возможное множественное перечисление IEnumerable" - PullRequest
20 голосов
/ 30 августа 2011

В SO есть вопрос о "возможных многократных перечислениях" , но этот вопрос более конкретен.

Пожалуйста, рассмотрите следующий метод, который принимает IEnumerable<string> в качестве входных данных ивыполняет данный метод для каждого из его элементов:

public static bool SomeMethod(IEnumerable<string> enumerable)
{
    if (enumerable.IsNullOrEmpty())
    {
        // throw exception.
    }
    else
    {
        return (enumerable.All(SomeBooleanMethod));
    }
}

В приведенном выше коде IsNullOrEmpty это просто метод расширения, который запускает

return (!ReferenceEquals(enumerable, null) || enumerable.Any());

Проблема в том, что ReSharper предупреждаетменя о "Возможных множественных перечислениях IEnumerable", и я действительно не знаю, может ли это быть на самом деле проблемой или нет.

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

Ответы [ 2 ]

30 голосов
/ 30 августа 2011

Это означает, что вы (частично) перебираете IEnumerable более одного раза: сначала при вызове Any() (который должен по крайней мере инициализировать итерацию, чтобы увидеть, возвращает ли перечисляемый какой-либо элемент), и второй разв All (который повторяется с начала).

Причина, по которой ReSharper предупреждает вас об этом, заключается в том, что перечисление по перечисляемому может вызвать побочные эффекты, а непреднамеренная повторение дважды может вызвать побочные эффекты дважды, что может илиможет быть нежелательным.

8 голосов
/ 02 сентября 2011

Как идентифицирует @tdammers, упоминаемые "множественные перечисления" - это два перечисления, требуемые Any и All.Поскольку вы хотите отклонить пустую последовательность, лучшее, что я могу придумать, это:

public static bool SomeMethod(IEnumerable<string> enumerable)
{
    if (enumerable == null)
        throw new ArgumentNullException();

    // Manually perform an All, keeping track of if there are any elements
    bool anyElements = false;

    bool result = true;

    foreach (string item in enumerable)
    {
        anyElements = true;
        result = result && SomeBooleanMethod(item);

        // Can short-circuit here
        if (!result)
            break;
    }

    if (!anyElements)
        throw new ArgumentException();    // Empty sequence is invalid argument

    return result;
}
...