代码
public static TSource Single<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
throw Error.ArgumentNull("source");
if (predicate == null)
throw Error.ArgumentNull("predicate");
TSource source1 = default (TSource);
long num = 0L;
foreach (TSource source2 in source)
{
if (predicate(source2))
{
source1 = source2;
checked { ++num; }
}
}
switch (num)
{
case 0L:
throw Error.NoMatch();
case 1L:
return source1;
default:
throw Error.MoreThanOneMatch();
}
}
所以问题是:为什么不在有多个匹配的元素时抛出异常?因此,例如,如果我们有一个大集合,我们可以得到一个很大的性能问题。为什么不在代码中编写简单的if
?例如:
public static class LinqTester
{
public static TSource MySingle<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
throw new ArgumentNullException("source");
if (predicate == null)
throw new ArgumentNullException("predicate");
TSource result = default(TSource);
int count = 0;
foreach (TSource value in source)
{
if (predicate(value))
{
checked { ++count; }
if (count > 1)
throw new Exception("MoreThanOneMatch");
result = value;
}
}
if (count == 0)
throw new Exception("NoMatch");
return result;
}
}
测试:
static void Main(string[] args)
{
var arr = new byte[100000000];
var sw = Stopwatch.StartNew();
try
{
Console.WriteLine(arr.Single(i => i == 0));
}
catch (Exception)
{
sw.Stop();
}
finally
{
Console.WriteLine(sw.Elapsed);
}
var sw2 = Stopwatch.StartNew();
try
{
Console.WriteLine(arr.MySingle(i => i == 0));
}
catch (Exception)
{
sw2.Stop();
}
finally
{
Console.WriteLine(sw2.Elapsed);
}
Console.WriteLine("Difference = {0}", (double) sw.ElapsedTicks/sw2.ElapsedTicks);
}
结果:
我改写了原版Single,因为mono的另一个实现只慢了3.5倍。