Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Even "IsNullOrEmpty" checks give "Possible multiple enumeration of IEnumerable" warnings

Tags:

There's a question on SO about "possible multiple enumerations" already, but this question is more specific.

Please consider the following method, which takes an IEnumerable<string> as input and executes a given method against each of its elements:

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

In the code above, IsNullOrEmpty is just an extension method which runs

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

The problem is that ReSharper is warning me about "Possible multiple enumerations of IEnumerable", and I really don't know if this can actually be a problem or not.

I understand the meaning of the warning, but what could you really do in this situation if you really need to check and throw exception in case of nullity or emptyness?

like image 545
User Avatar asked Aug 30 '11 13:08

User


2 Answers

It means that you are (partially) iterating over the IEnumerable more than once: first in your call to Any() (which needs to at least initialize an iteration to see if the enumerable returns any elements), and a second time in All (which iterates from the beginning).

The reason ReSharper warns you about this is that enumerating over an enumerable may cause side effects, and unintentionally iterating twice may trigger the side effects twice, which may or may not be desirable.

like image 92
tdammers Avatar answered Oct 16 '22 05:10

tdammers


As @tdammers identifies, the "multiple enumerations" referred to are the two enumerations required by Any and All. Since you want to reject an empty sequence, the best I can come up with is:

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;
}
like image 41
AakashM Avatar answered Oct 16 '22 05:10

AakashM