Why does Enumerable.All return true for an empty sequence? [duplicate]

北城余情 提交于 2019-11-26 16:12:58

It's certainly not a bug. It's behaving exactly as documented:

true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false.

Now you can argue about whether or not it should work that way (it seems fine to me; every element of the sequence conforms to the predicate) but the very first thing to check before you ask whether something is a bug, is the documentation. (It's the first thing to check as soon as a method behaves in a way other than what you expected.)

All requires the predicate to be true for all elements of the sequence. This is explicitly stated in the documentation. It's also the only thing that makes sense if you think of All as being like a logical and between the predicate's results for each element. The "true" you're getting out for the empty sequence is the identity element of the and operation. Likewise, the false you get from Any for the empty sequence is the identity for logical or.

If you think of "all" as being "there are no elements in the sequence that are not", this might make more sense.

It is true, as nothing (no condition) makes it false.

The docs probably explain it. (Jon Skeet also mentioned something a few years back)

Same goes for Any (the opposite of All) returning false for empty sets.

Edit:

You can imagine All to be implemented semantically the same as:

foreach (var e in elems)
{
  if (!cond(e))
    return false;
}
return true; // no escape from loop

The method cycles through all elements until it finds one that does not satisfy the condition, or finds none that fail. If none fail, true is returned.

So, if there are no elements, true is returned (since there were none that failed)

Most answers here seem to go along the lines of "because that's how is defined". But there is also a logical reason why is defined this way.

When defining a function, you want your function to be as general as possible, such that it can be applied to the largest possible number of cases. Say, for instance, that I want to define the Sum function, which returns the sum of all the numbers in a list. What should it return when the list is empty? If you'd return an arbitrary number x, you'd define the function as the:

  1. Function that returns the sum of all numbers in the given list, or x if the list is empty.

But if x is zero, you can also define it as the

  1. Function that returns x plus the given numbers.

Note that definition 2 implies definition 1, but 1 does not imply 2 when x is not zero, which by itself is enough reason to pick 2 over 1. But also note 2 is more elegant and, in its own right, more general than 1. Is like placing a spotlight farther away so that it lightens a larger area. A lot larger actually. I'm not a mathematician myself but I'm sure they'll find a ton of connections between definition 2 and other mathematical concepts, but not so many related to definition 1 when x is not zero.

In general, you can, and most likely want to return the identity element (the one that leaves the other operand unchanged) whenever you have a function that applies a binary operator over a set of elements and the set is empty. This is the same reason a Product function will return 1 when the list is empty (note that you could just replace "x plus" with "one times" in definition 2). And is the same reason All (which can be thought of as the repeated application of the logical AND operator) will return true when the list is empty (p && true is equivalent to p), and the same reason Any (the OR operator) will return false.

Keeping the implementation aside. Does it really matter if it is true? See if you have some code which iterates over the enumerable and executes some code. if All() is true then that code is still not going to run since the enumerable doesn't have any elements in it.

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.

Here is an extension that can do what OP wanted to do:

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;
}

...and as others have pointed out already this is not a bug but well-documented intended behavior.

An alternative solution if one does not wish to write a new extension is:

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

PS: The above does not work if looking for the default value itself! (Which for strings would be null.) In such cases it becomes less elegant with something similar to:

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

If you can enumerate more than once the easiest solution is:

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

i.e simply add a check after that there actually were any element.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!