Why does Single() not return directly when more than one element is found? [duplicate]

谁都会走 提交于 2019-12-23 06:52:08

问题


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

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