Я наткнулся на эту реализацию в Enumerable.cs с помощью отражателя.
public static TSource Single<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
//check parameters
TSource local = default(TSource);
long num = 0L;
foreach (TSource local2 in source)
{
if (predicate(local2))
{
local = local2;
num += 1L;
//I think they should do something here like:
//if (num >= 2L) throw Error.MoreThanOneMatch();
//no necessary to continue
}
}
//return different results by num's value
}
Я думаю, что они должны разорвать цикл, если есть более двух элементов, удовлетворяющих условию, почему они всегда проходят цикл коллекция? В случае, если этот отражатель неправильно дизассемблирует dll, я пишу простой тест:
class DataItem
{
private int _num;
public DataItem(int num)
{
_num = num;
}
public int Num
{
get{ Console.WriteLine("getting "+_num); return _num;}
}
}
var source = Enumerable.Range(1,10).Select( x => new DataItem(x));
var result = source.Single(x => x.Num < 5);
Я думаю, что для этого тестового случая он напечатает «получение 0, получение 1», а затем выдаст исключение. Но правда в том, что он продолжает «получать 0 ... получать 10» и выдает исключение. Есть ли какая-то алгоритмическая причина, по которой они реализуют этот метод таким образом?
РЕДАКТИРОВАТЬ Некоторые из вас думали, что это из-за побочных эффектов выражения предиката , после глубоких размышлений и некоторых тестовых примеров у меня есть вывод о том, что побочные эффекты в данном случае не имеют значения . Если вы не согласны с этим выводом, приведите пример.