问题
I found (roughly) this code in the Enumerable.Single method while inspecting it with some decompiler:
foreach (TSource current in source)
{
if (predicate(current))
{
result = current;
num += 1L;
}
}
if (num > 1L)
{
throw Error.MoreThanOneMatch();
}
As you can see, it loops over all items before throwing. Why doesn't it break when num > 1
?
回答1:
Agree, that it will be better from terms of performance (EDIT: if we are expecting more than one item matching our predicate, which we should not do):
foreach (TSource current in source)
{
if (predicate(current))
{
result = current;
num += 1L;
if (num > 1L)
throw Error.MoreThanOneMatch();
}
}
if (num == 0L)
throw Error.NoMatch();
return local;
Looks like they decided to make results analyzing more clear and separated it from enumerating source. But then I wonder why simple switch was not used:
switch((int)num)
{
case 0: throw Error.NoMatch();
case 1: return local;
default:
throw Error.MoreThanOneMatch();
}
Regarding to performance issues - I think it's assumed that Single
should be called when you are really expecting single result. Zero or more results is an exceptional path, which should not occur often (as any exception). So, it's more your program's logic error if source contain many items matching predicate.
回答2:
By Single
is meant, exactly one, not none and also not more than one.
It enumerates all items, to ensure that it's only one.
It throws an exception, if there is none or more than one.SingleOrDefault
instead throws if there are more, but returns default(T)
/null
if there is none.
What you're looking for is FirstOrDefault
that breaks the enumeration, if it found the first one matching the predicate. First
instead throws if there is none, and also breaks (directly returns from) it's foreach, if it found the first one.
FirstOrDefault's source
foreach (TSource current in source)
{
if (predicate(current))
{
return current;
}
}
return default(TSource);
Whereas First's source is instead of return default
throw Error.NoMatch();
来源:https://stackoverflow.com/questions/17743231/why-does-single-not-return-directly-when-more-than-one-element-is-found