var strs = new Collection<string>();
bool b = strs.All(str => str == "ABC");
代码创建了一个空字符串集合,然后试图确定集合中的所有元素是否都为"ABC"。如果运行它,b
将会是true。但是这个集合甚至没有任何元素,更不用说有任何等于"ABC"的元素了。
这是一个bug吗?还是有一个合理的解释?
var strs = new Collection<string>();
bool b = strs.All(str => str == "ABC");
代码创建了一个空字符串集合,然后试图确定集合中的所有元素是否都为"ABC"。如果运行它,b
将会是true。这显然不是一个漏洞。它的行为恰恰符合文档所述:
如果源序列的每个元素都通过指定谓词中的测试,或者序列为空,则为 true;否则为 false。
现在你可以争论它是否应该这样工作(我觉得很好;序列的每个元素都符合谓词),但在询问某个东西是否有漏洞之前,第一件要检查的事情是文档。(当一个方法的行为与你预期的不同时,这是要检查的第一件事情。)
!Any(Predicate)
将不会与All(!Predicate)
相同,这将会非常令人费解。 - AniAll
需要对序列中的所有元素都满足谓词条件。这在文档中明确说明了。如果你把All
看作是在每个元素的谓词结果之间执行逻辑“与”操作,那么只有满足所有元素才有意义。对于空序列返回的true
是逻辑“与”操作的恒等元素,而Any
对于空序列返回的false
是逻辑“或”的恒等元素。
如果你把All
看作是“序列中没有不满足条件的元素”,可能会更容易理解。
对于所有X,P(X)
和存在X,~P(X)
[在逻辑上等价](http://en.wikipedia.org/wiki/Universal_quantification#Negation)。 - Brian如果没有任何条件可以使其为false
,那么它就是true
。
文档可能已经解释了这点。 (Jon Skeet几年前也提到过一些东西)
Any
(与All
相反)对于空集返回false
,同样适用。
编辑:
您可以想象All
的语义实现方式与以下代码相同:
foreach (var e in elems)
{
if (!cond(e))
return false;
}
return true; // no escape from loop
Sum
函数。当列表为空时,应该返回什么?如果返回任意数字x
,则将函数定义为:x
(当列表为空时)。x
定义为零,则还可以将其定义为:x
加上给定数字的函数。x
不为零时,1不暗示2,这本身就足以选择2而不是1。但是请注意,2更加优雅且更通用。就好像将聚光灯放得更远,以照亮更大的区域一样。实际上要大得多。我自己不是数学家,但我确定他们会在定义2和其他数学概念之间找到大量联系,但与当x
不为零时的定义1相关的联系会较少。Product
函数将返回1的原因(请注意,您可以在定义2中用“一次乘以”替换“x
加”)。并且也是All
(可以被视为逻辑AND运算符的重复应用)在列表为空时将返回true
的原因(p && true
等价于p
),以及Any
(OR运算符)将返回false
的原因。这里有一个扩展程序可以实现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:如果要查找默认值本身,则上述方法无效!(对于字符串,它是null。)在这种情况下,可以使用类似以下的代码:
strs.DefaultIfEmpty(string.Empty).All(str => str == null);
strs.All(predicate) && strs.Any();
也就是说,在检查是否存在任何元素之后,只需添加一个检查。
把实现放在一边,这是否真的很重要?如果您有一些代码遍历可枚举并执行某些代码,则如果 All() 为 true,则该代码仍然不会运行,因为可枚举没有任何元素。
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.
.First()
。 - Kenneth_hj
Any()
方法来返回false。 - Yuriy Faktorovich