即使是“IsNullOrEmpty”检查给出“IEnumerable 的可能多重枚举”警告

发布于 2024-12-01 21:02:24 字数 692 浏览 3 评论 0原文

已经有一个关于“可能的多重枚举”的问题,但这个问题更具体。

请考虑以下方法,该方法采用 IEnumerable 作为输入,并对其每个元素执行给定的方法:

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 枚举”,我真的不知道这是否真的是一个问题。

我理解警告的含义,但是如果您确实需要检查并在空或空的情况下抛出异常,那么在这种情况下您真正能做什么?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

長街聽風 2024-12-08 21:02:24

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

ReSharper 警告您这一点的原因是,枚举可枚举可能会导致副作用,并且无意中迭代两次可能会触发两次副作用,这可能是理想的,也可能不是理想的。

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.

薄荷港 2024-12-08 21:02:24

正如 @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;
}

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;
}
颜漓半夏 2024-12-08 21:02:24

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

Resharper 不会警告您,因为您正在调用 Any()All()。它警告您,因为您正在调用 IsNullOrEmpty()All()。事实上,Resharper 甚至不知道您正在调用 Any()。尝试删除它 - 您会发现您仍然收到警告。

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

这很微妙但很重要。在您的情况下,警告很有用,因为您枚举了两次。但也许您的扩展方法不枚举可枚举项,并且您知道可以忽略该警告。在这种情况下,Resharper 会为您提供 NoEnumeration Resharper 代码注释中的属性

这允许您标记枚举,如下所示 。配制方法如下:

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

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文