127
var strs = new Collection<string>();
bool b = strs.All(str => str == "ABC");

该代码创建一个空字符串集合,然后尝试确定集合中的所有元素是否都是“ABC”。如果你运行它,b将是真的。

但是该集合中甚至没有任何元素,更不用说任何等于“ABC”的元素了。

这是一个错误,还是有合理的解释?

4

7 回答 7

190

这当然不是一个错误。它的行为与记录的完全相同:

如果源序列的每个元素都通过了指定谓词中的测试,或者序列为空,则为 true ;否则为假。

现在您可以争论它是否应该以这种方式工作(对我来说这似乎很好;序列的每个元素都符合谓词)但是在您询问某事是否是错误之前,首先要检查的是文档。(一旦方法的行为与您预期的不同,这是首先要检查的事情。)

于 2011-10-25T05:32:40.443 回答
14

All要求谓词对于序列的所有元素都为真。这在文档中明确说明。All如果您将每个元素的谓词结果视为逻辑“与”,这也是唯一有意义的事情。true您为空序列而退出的是“与”操作的标识元素。同样,false您从中获得Any的空序列是逻辑“或”的标识。

如果您认为All“序列中没有不存在的元素”,这可能更有意义。

于 2011-10-25T05:10:28.450 回答
10

它是true,因为没有(没有条件)使它成为false

文档可能会解释它。(Jon Skeet 几年前也提到过一些事情)

对于空集返回Any(相反)也是如此。Allfalse

编辑:

您可以想象All在语义上与以下内容相同:

foreach (var e in elems)
{
  if (!cond(e))
    return false;
}
return true; // no escape from loop
于 2011-10-25T05:04:21.210 回答
6

这里的大多数答案似乎都遵循“因为这就是定义”的思路。但是这样定义也有一个合乎逻辑的原因。

定义函数时,您希望函数尽可能通用,以便它可以应用于尽可能多的情况。例如,假设我想定义一个Sum函数,它返回列表中所有数字的总和。当列表为空时它应该返回什么?如果您要返回一个任意数字x,您可以将函数定义为:

  1. 返回给定列表中所有数字之和的函数,或者x如果列表为空。

但如果x为零,您也可以将其定义为

  1. 返回x加上给定数字的函数。

请注意,定义 2 暗示了定义 1,但 1 在x不为零时并不暗示 2,这本身就是选择 2 而不是 1 的充分理由。但是注意 2更优雅,就其本身而言,比 1 更一般。就像将聚光灯放在更远的地方,以便照亮更大的区域。实际上要大很多。我自己不是数学家,但我相信他们会在定义 2 和其他数学概念之间找到大量联系,但当x不为零时,与定义 1 相关的联系并不多。

通常,只要您有一个函数对一组元素应用二元运算符并且该集合为空,您就可以并且很可能希望返回标识元素(使另一个操作数保持不变的元素)。这Product与列表为空时函数将返回 1 的原因相同(请注意,您可以x在定义 2 中将“加号”替换为“一次”)。And is 同样的原因All(可以认为是逻辑 AND 运算符的重复应用)将true在列表为空时返回(p && true相当于p),同样的原因Any(OR 运算符)将返回false

于 2015-08-23T14:30:23.213 回答
3

该方法循环遍历所有元素,直到找到不满足条件的元素,或者找到不满足条件的元素。如果没有失败,则返回 true。

因此,如果没有元素,则返回 true(因为没有失败的元素)

于 2011-10-25T05:04:32.747 回答
3

这是一个可以做 OP 想做的扩展:

static bool All<T>(this IEnumerable<T> source, Func<T, bool> predicate, bool mustExist)
{
    foreach (var e in source)
    {
        if (!predicate(e))
            return false;
        mustExist = false;
    }
    return !mustExist;
}

...正如其他人已经指出的那样,这不是一个错误,而是有据可查的预期行为。

如果不想编写新的扩展,另一种解决方案是:

strs.DefaultIfEmpty().All(str => str == "ABC");

PS:如果自己找默认值,上面的不行!(对于字符串来说,这将是空的。)在这种情况下,它会变得不那么优雅,类似于:

strs.DefaultIfEmpty(string.Empty).All(str => str == null);

如果您可以多次枚举,最简单的解决方案是:

strs.All(predicate) && strs.Any();

即在实际上有任何元素之后简单地添加一个检查。

于 2016-01-24T21:14:57.683 回答
1

将实施搁置一旁。如果它是真的,这真的很重要吗?看看你是否有一些代码迭代可枚举并执行一些代码。如果 All() 为真,那么该代码仍然不会运行,因为可枚举中没有任何元素。

var hungryDogs = Enumerable.Empty<Dog>();
bool allAreHungry = hungryDogs.All(d=>d.Hungry);    
if (allAreHungry)
    foreach (Dog dog in hungryDogs)
         dog.Feed(biscuits); <--- this line will not run anyway.
于 2011-10-25T05:19:30.787 回答