我在Enumerable.Single
方法中发现(大致)这段代码,同时用一些反编译器检查它:
foreach (TSource current in source)
{
if (predicate(current))
{
result = current;
num += 1L;
}
}
if (num > 1L)
{
throw Error.MoreThanOneMatch();
}
正如您所看到的,它会在投掷之前循环遍历所有项目。为什么num > 1
时它不会中断?
答案 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();