.net - 为什么 IQueryable.All() 在空集合上返回 true?

标签 .net linq logic

所以我今天遇到了一种情况,一些生产代码失败正是因为一个方法的执行完全像documented in MSDN 。为我没有阅读文档而感到羞耻。然而,我仍然摸不着头脑为什么它会这样,即使是“设计使然”,因为这种行为与我的预期(以及其他已知的行为)完全相反,并且因此似乎违反了最小意外原则。

All() 方法允许您提供谓词(例如 lambda 表达式)来测试 IQueryable,返回一个 bool 值,指示是否所有集合成员匹配测试。到目前为止,一切都很好。这就是奇怪的地方。如果集合为空,All() 也会返回 true。这对我来说似乎完全倒退,原因如下:

  • 如果集合为空,则这样的测试最多是未定义的。如果我的车道是空的,我不能断言停在那里的所有汽车都是红色的。通过这种行为,在空车道上停放的所有汽车都是红色、蓝色和棋盘 - 所有这些表达式都将返回 true。
  • 对于任何熟悉 NULL != NULL SQL 概念的人来说,这是意外的行为。
  • Any() 方法的行为符合预期,并且(正确地)返回 false,因为它没有任何与谓词匹配的成员。

所以我的问题是,为什么 All() 会这样?它解决什么问题?这是否违反了最小意外原则?

我将此问题标记为 .NET 3.5,但该行为也适用于 .NET 4.0。

编辑 好的,我掌握了这一点的逻辑方面,正如杰森和你们其他人出色地阐述的那样。诚然,空集合是一种边缘情况。我想我的问题源于这样的斗争:如果你的心态不正确,仅仅因为某件事是合乎逻辑的并不意味着它一定有意义。

最佳答案

If my driveway is empty, I cannot assert that all cars parked there are red.

考虑以下陈述。

S1: My driveway is empty.

S2: All the cars parked in my driveway are red.

我声称S1意味着S2 。即语句S1 => S2是真的。我将通过证明它的否定是错误的来做到这一点。在这种情况下, S1 => S2 的否定是 S1 ^ ~S2 ;这是因为S1 => S2仅当 S1 时为 false是真的并且 S2是假的。 S2的否定是什么?这是

~S2: There exists a car parked in my driveway that is not red.

S1 ^ ~S2的真值是多少?我们来写一下吧

S1 ^ ~S2: My driveway is empty and there exists a car parked in my driveway that is not red.

唯一的办法S1 ^ ~S2如果 S1 则为真和~S2是真的。但是S1说我的车道是空的并且 S2说我的车道上有一辆车。我的车道不能既是空的又包含汽车。因此,S1 是不可能的。和~S2两者都是真实的。因此,S1 ^ ~S2是假的,所以它的否定 S1 => S2是真的。

因此,如果您的车道是空的,您可以断言停在那里的所有汽车都是红色的。

现在让我们考虑 IEnumerable<T> elements和一个 Predicate<T> p 。让我们假设elements是空的。我们希望发现的值(value)

bool b = elements.All(x => p(x));

让我们考虑一下它的否定

bool notb = elements.Any(x => !p(x));

对于notb为真,必须至少有一个 xelements其中!p(x)是真的。但是elements是空的,所以不可能找到 x其中!p(x)是真的。因此notb不可能是真的,所以它一定是假的。自 notb为假,其否定为真。因此b是真的并且 elements.All(x => p(x))如果 elements 则必须为 true为空。

这里还有另一种思考方式。谓词p如果对于全部 x 则为真在elements您无法找到任何错误的内容。但如果 elements 中没有任何项目那么就不可能找到任何它是错误的。因此,对于空集合 elements , p对于所有都是如此xelements

现在,elements.Any(x => p(x)) 怎么样?当elements是空的IEnumerable<T>pPredicate<T>如上?我们已经知道结果将是假的,因为我们知道它的否定是真的,但无论如何让我们通过它进行推理;直觉是有值(value)的。对于 elements.Any(x => p(x))为真必须至少有一个 xelements其中p(x)是真的。但如果没有任何xelements不可能找到任何 x其中p(x)是真的。因此,elements.Any(x => p(x))如果 elements 则为 false为空。

最后,这是一个 related explanation为什么s.StartsWith(String.Empty)s时为真是 string 的非空实例:

关于.net - 为什么 IQueryable.All() 在空集合上返回 true?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2195289/

相关文章:

c# - 如何在sql查询中添加一个条件来检查复选框是否被选中?

c# - Linq:从子列表中选择第一项?

c# - 使用 Dapper 在 Linq 中进行多对多

c# - 创建新动态对象时的内联操作

java - 线程主错误中的异常

mysql - 需要在mysql中按数据分组

.net - 支持存储过程的 MS(正在进行?)嵌入式(无服务器)SQL Server 版本的名称是什么?

c# - 在 xml 文档中,我可以插入对方法组的引用吗?如何?

c# - 在面向 .NET 4+ 的库中公开通知时,IObservable 是否应该优先于事件

java - 按频率或计算时间排序的条件语句?