код из ссылок .Net
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);
}
полученные результаты:
Я переписал оригинальный сингл, потому что моно имеет другую реализацию, всего в 3,5 раза медленнее.
Single()
не вызовет исключение. Дизайнеры решили оптимизировать для успеха, а не для неудач. - person Scott Chamberlain   schedule 28.05.2014Single()
, потому что в обычном случае операторif
будет проверяться только один раз для одного совпадающего элемента. И непонятно, почемуSingle(IEnumerable<T>)
повысил производительность, аSingle(IEnumerable<T>,Predicate<T>)
- нет. - person Alex Zhukovskiy   schedule 28.05.2014