开发者

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

开发者 https://www.devze.com 2023-03-31 14:13 出处:网络
There\'s a question on SO about \"possible multiple enumerations\" already, but this question is more specific.

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开发者_Python百科 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?


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.


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;
}


Whilst the other answers here are correct in that you are enumerating twice (and the potential harm in doing so), they are both (subtly) incorrect as to why you are getting the warning.

Resharper is not warning you because you are calling Any() and All(). It is warning you because you are calling IsNullOrEmpty() and All(). In fact, Resharper doesn't even know you are calling Any().Try removing it - you will find you still get the warning.

This is because Resharper has no idea what happens to an enumerable which is passed to another method. Maybe that other method enumerates it, maybe not. But you are passing the enumerable to two methods, so maybe they both enumerate it, so maybe it is enumerated twice. Hence the warning, "Possible multiple enumeration'.

This is subtle but important. In your case, the warning was useful, because you were enumerating twice. But maybe your extension method doesn't enumerate the enumerable and you know the warning can be ignored. In this case, Resharper provides you with the NoEnumeration attribute in Resharper's Code Annotations.

This allows you to tag an enumerable, as in the following made up method:

public static bool IsNull<T>([NoEnumeration]this IEnumerable<T> enumerable)
{
    return enumerable is null;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消