为什么Single()不会在找到多个元素时直接返回?

时间:2013-07-19 09:56:55

标签: c# .net linq internals

我在Enumerable.Single方法中发现(大致)这段代码,同时用一些反编译器检查它:

foreach (TSource current in source)
{
    if (predicate(current))
    {
        result = current;
        num += 1L;
    }
}

if (num > 1L)
{
     throw Error.MoreThanOneMatch();
}

正如您所看到的,它会在投掷之前循环遍历所有项目。为什么num > 1时它不会中断?

2 个答案:

答案 0 :(得分:4)

同意,从性能条款来看会更好(编辑:如果我们期望不止一个项匹配我们的谓词,我们不应该这样做):

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;

看起来他们决定让结果分析更清晰,并将其与枚举源分开。但后来我想知道为什么没有使用简单的开关:

switch((int)num)
{
   case 0: throw Error.NoMatch();
   case 1: return local;
   default:
       throw Error.MoreThanOneMatch();    
}

关于性能问题 - 我认为当你真正期待单一结果时,应该调用Single。零或多个结果是特殊路径,不应经常发生(如任何异常)。因此,如果源包含许多与谓词匹配的项目,则更多是程序的逻辑错误。

答案 1 :(得分:0)

Single表示,正好一个,不是一个,也不会多于一个
它枚举所有项目,确保它只有一个。
如果没有或多于一个,则抛出异常。
如果有更多内容,则SingleOrDefault会抛弃,但如果没有,则返回default(T) / null

如果找到第一个与谓词匹配的枚举,那么你要查找的是FirstOrDefault,它会打破枚举。 First如果没有,则会抛出,如果找到第一个,也会断开(直接返回)它的foreach。

FirstOrDefault的来源

foreach (TSource current in source)
{
    if (predicate(current))
    {
        return current;
    }
}
return default(TSource);

而First的源代替返回默认值

throw Error.NoMatch();