即使“ IsNullOrEmpty”检查也会给出“可能对IEnumerable进行多重枚举的警告”

问题描述 投票:20回答:3

已经有一个question on SO about "possible multiple enumerations",但是这个问题更具体。

请考虑以下方法,该方法将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的多个枚举”,我真的不知道这是否可能是一个问题。

我理解警告的含义,但是如果您真的需要检查并抛出异常(如果为空或为空的话),您在这种情况下会真正地做什么?

c# resharper ienumerable
3个回答
30
投票

这意味着您(部分)对IEnumerable进行了多次迭代:首先在对Any()的调用中(它至少需要初始化一个迭代以查看可枚举是否返回任何元素),而第二次是All(从头开始迭代)。

ReSharper对此警告您的原因是,枚举一个枚举可能会导致副作用,而无意地重复两次可能会触发两次副作用,这可能是不希望的,或者是不希望的。


8
投票

正如@tdammers所标识的,所指的“多个枚举”是AnyAll所需的两个枚举。由于您想拒绝一个空序列,因此我能想到的最好的方法是:

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

0
投票

虽然这里的其他答案是正确的,因为您要枚举两次(以及这样做的潜在危害),但是对于您得到警告的原因,它们都(有点)不正确。

Resharper不会警告您,因为您正在呼叫Any()All()。这是警告您,因为您正在调用IsNullOrEmpty()All()。实际上,Resharper甚至不认识您are呼叫Any()。尝试将其删除-您会发现您仍然收到警告。

这是因为Resharper有no idea传递给另一个方法的可枚举发生了什么。也许其他方法枚举了它,也许不是。但是您将枚举方法传递给了两种方法,因此也许它们都枚举了它,所以也许它被枚举了两次。因此,警告为“ << [可能多重枚举”。

这很微妙,但很重要。在您的情况下,该警告很有用,因为您

枚举两次。但是也许您的扩展方法没有枚举可枚举,并且您know警告可以忽略。在这种情况下,Resharper为您提供NoEnumeration attribute in Resharper's Code Annotations这使您可以标记枚举,如下面的组合方法所示:

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

© www.soinside.com 2019 - 2024. All rights reserved.