为什么IQueryable.All()返回true一个空集? [英] Why does IQueryable.All() return true on an empty collection?

查看:112
本文介绍了为什么IQueryable.All()返回true一个空集?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我今天遇到了一个情况:一些生产code的失败precisely因为一个方法来执行完全一样的记录在MSDN 。可耻的是我没有阅读文档。不过,我仍然抓我的头,以为什么的它的行为这样一来,即使设计,因为这种行为是完全相反的我本来期望(和其他已知的行为)和因此,似乎违反了最小惊讶的原则。

所有()方法,可以提供一个predicate(如一个lambda EX pression)来测试 IQueryable的,返回一个布尔值,指示是否所有集合成员匹配测试。到目前为止,一切都很好。这里是会很奇怪。 所有()也返回如果集合是空的。这似乎完全倒退到我,原因如下:

  • 如果集合为空,这样的测试,在最好的,不确定的。如果我的车道是空的,我不能断言所有的车停在那里是红色的。有了这种行为,在一个空的车道全车停有红蓝棋盘 - 所有这些EX pressions会返回true
  • 对于任何熟悉SQL的概念,NULL!= NULL,这是意外的行为。
  • 任何()方法的行为预期,和(正确)返回false,因为它不具有匹配的predicate的任何成员。

我的问题是,为什么所有()行为这种方式?它解决什么问题?这是否违反了最小惊讶的原则?

我标记这个问题作为.NET 3.5,虽然行为也适用于.NET 4.0为好。

修改确定,所以我把握逻辑方面这一点,因为这样出色奠定了由Jason和你休息。诚然,一个空集是值得的边缘情况。我想我的问题是植根于斗争,只是因为东西的逻辑的,并不意味着它必然使的感觉的,如果你没有记住正确的框架。

解决方案
  

如果我的车道是空的,我不能断言所有的车停在那里是红色的。

考虑下面的语句。

  

S1 :我的车道是空的。

     

S2 :所有的停在我的车道上的车是红色的

我宣称 S1 意味着 S2 。也就是说,该语句 S1 => S2 是真实的。我将通过展示,它的否定是假的做到这一点。在这种情况下,否定 S1 => S2 S1 ^〜S2 ;这是因为 S1 => S2 是假的,只有当 S1 的真实, S2 是假的。什么是 S2 的否定?这是

  

〜S2 :存在一个车子停在我的车道上,是不是红

什么是 S1 ^〜S2 的真值?让我们写出来

  

S1 ^〜S2 :我的车道是空的,存在一个车子停在我的车道上,是不是红

的唯一方法是 S1 ^〜S2 可真就是如果两个 S1 〜S2 是真实的。但 S1 说,我的车道是空的, S2 表示,存在一个车在我的车道上。我的车道不能为空以及包含汽车。因此,这是不可能的 S1 〜S2 这两个是真实的。因此, S1 ^〜S2 是false,所以它的否定 S1 => S2 是真实的。

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

所以,现在让我们来考虑一个的IEnumerable< T>元素 predicate< T> P 。让我们假设元素是空的。我们要探索的价值

 布尔B = elements.All(X => P(x));
 

让我们看看它的否定

 布尔notb = elements.Any(X =>!P(x));
 

有关 notb 是真实的,必须有至少有一个 X 元素为其!p(x)是真实的。但元素是空的,所以它是不可能找到一个 X 为其!P(x )是真实的。因此 notb 不可能是真实的,因此一定是假的。由于 notb 为假,它的否定是真实的。因此 B 的真实, elements.All(X => P(x))必须是真实的,如果元素是空的。

下面是想到另外一个问题的方式。在predicate P 是真实的,如果对的所有 X 元素你找不到的任意的为它是假的。但是,如果在元素中没有商品那么它是不可能找到的任意的为它是假的。因此,对于一个空的集合元素 P 是如此的所有 X 元素

现在,有关 elements.Any什么(X =&GT; P(x))元素是一个空的IEnumerable&LT; T&GT; P predicate&LT; T&GT; 如上?我们已经知道结果会是假的,因为我们知道它的否定是真实的,但让我们有理由通过它无论如何;直觉是有价值的。对于 elements.Any(X =&GT; P(x))是真实的,必须有至少有一个 X 元素为其 P(x)是真实的。但是,如果没有的<​​em>任意的 X 元素这是不可能找到的任何 X 为其 P(x)是真实的。因此, elements.Any(X =&GT; P(x))是假的,如果元素是空

最后,这里有一个<一个href="http://stackoverflow.com/questions/145509/why-does-abcd-startswith-return-true/390801#390801">related为什么 s.StartsWith(的String.Empty)是真实的,当取值是一个非空的解释 字符串的实例:

So I ran into a situation today where some production code was failing precisely because a method performed exactly as documented in MSDN. Shame on me for not reading the documentation. However, I'm still scratching my head as to why it behaves this way, even if "by design", since this behavior is exactly opposite what I would have expected (and other, known behaviors) and therefore seems to violate the principle of least surprise.

The All() method allows you to supply a predicate (such as a lambda expression) to test an IQueryable, returning a Boolean value that indicates whether all collection members match the test. So far so good. Here's where it gets weird. All() also returns true if the collection is empty. This seems completely backwards to me, for the following reasons:

  • If the collection is empty, a test like this is, at best, undefined. If my driveway is empty, I cannot assert that all cars parked there are red. With this behavior, on an empty driveway all cars parked there are red AND blue AND checkerboard - all of these expressions would return true.
  • For anyone familiar with the SQL notion that NULL != NULL, this is unexpected behavior.
  • The Any() method behaves as expected, and (correctly) returns false because it does not have any members that match the predicate.

So my question is, why does All() behave this way? What problem does it solve? Does this violate the principle of least surprise?

I tagged this question as .NET 3.5, though the behavior also applies to .NET 4.0 as well.

EDIT Ok, so I grasp the logic aspect to this, as so excellently laid out by Jason and the rest of you. Admittedly, an empty collection is something of an edge case. I guess my question is rooted in the struggle that, just because something is logical doesn't mean it necessarily makes sense if you're not in the correct frame of mind.

解决方案

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

Consider the following statements.

S1: My driveway is empty.

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

I claim that S1 implies S2. That is, the statement S1 => S2 is true. I will do this by showing that it's negation is false. In this case, the negation of S1 => S2 is S1 ^ ~S2; this is because S1 => S2 is false only when S1 is true and S2 is false. What is the negation of S2? It is

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

What is the truth value of S1 ^ ~S2? Let's write it out

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

The only way that S1 ^ ~S2 can be true is if both S1 and ~S2 are true. But S1 says that my driveway is empty and S2 says that there exists a car in my driveway. My driveway can not be both empty and contain a car. Thus, it is impossible for S1 and ~S2 to both be true. Therefore, S1 ^ ~S2 is false so its negation S1 => S2 is true.

Therefore, if your driveway is empty you can assert that all cars parked there are red.

So now let's consider an IEnumerable<T> elements and a Predicate<T> p. Let us suppose that elements is empty. We wish to discover the value of

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

Let's consider its negation

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

For notb to be true, there must be at least one x in elements for which !p(x) is true. But elements is empty so it is impossible to find an x for which !p(x) is true. Therefore notb can not be true so it must be false. Since notb is false, its negation is true. Therefore b is true and elements.All(x => p(x)) must be true if elements is empty.

Here's one more way to think of this. The predicate p is true if for all x in elements you can not find any for which it is false. But if there are no items in elements then it is impossible to find any for which it is false. Thus, for an empty collection elements, p is true for all x in elements

Now, what about elements.Any(x => p(x)) when elements is an empty IEnumerable<T> and p is a Predicate<T> as above? We already know the result will be false because we know its negation is true, but let's reason through it anyway; the intuition is valuable. For elements.Any(x => p(x)) to be true there must be at least one x in elements for which p(x) is true. But if there aren't any x in elements it is impossible to find any x for which p(x) is true. Therefore, elements.Any(x => p(x)) is false if elements is empty.

Finally, here's a related explanation on why s.StartsWith(String.Empty) is true when s is a non-null instance of string:

这篇关于为什么IQueryable.All()返回true一个空集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆