Обновление:
Я получил очень хороший отзыв на мой ответ, который заставил меня переосмыслить. Таким образом, я сначала предоставлю ответ, который излагает мою «новую» точку зрения; Вы все еще можете найти мой оригинальный ответ чуть ниже. Обязательно прочитайте промежуточные комментарии, чтобы понять, где мой первый ответ не соответствует сути.
Новый ответ:
Предположим, что Single
должно выдать исключение, когда его предварительное условие не выполнено; то есть, когда Single
обнаруживает, что ни одно, или более одного элемента в коллекции соответствует предикату.
Single
может быть успешным без исключения, только пройдя всю коллекцию. Он должен удостовериться, что имеется только один соответствующий элемент, поэтому он должен проверить все элементы в коллекции.
Это означает, что раннее создание исключения (как только он найдет второй соответствующий элемент) - это, по сути, оптимизация, от которой вы можете извлечь выгоду только тогда, когда предварительное условие Single
не может быть выполнено и когда оно сгенерирует исключение .
Как ясно указывает пользователь CodeInChaos в комментарии ниже, оптимизация не будет неправильной, но она не имеет смысла, поскольку обычно вводятся оптимизации, которые будут полезны для корректно работающего кода, а не оптимизации, которые будут приносить пользу неисправному коду.
Таким образом, действительно правильно, что Single
может вызвать исключение раньше; но это не обязательно, потому что практически нет дополнительной выгоды.
Старый ответ:
Я не могу дать техническую причину , почему этот метод реализован таким, какой он есть, поскольку я его не реализовал. Но я могу высказать свое понимание цели оператора Single
, и отсюда сделать мой личный вывод, что она действительно плохо реализована:
Мое понимание Single
:
Какова цель Single
и чем она отличается, например, от First
или Last
?
Использование оператора Single
в основном выражает предположение, что из коллекции должен быть возвращен ровно один элемент:
Если вы не укажете предикат, это должно означать, что коллекция должна содержать ровно один элемент.
Если вы укажете предикат, это должно означать, что ровно один элемент в коллекции должен удовлетворять этому условию. (Использование предиката должно иметь тот же эффект, что и items.Where(predicate).Single()
.)
Это то, что отличает Single
от других операторов, таких как First
, Last
или Take(1)
. Ни у одного из этих операторов не должно быть точно одного (соответствующего) элемента.
Когда Single
должен выдать исключение?
В основном, когда обнаруживается, что ваше предположение было неверным; т.е. когда базовая коллекция не дает ровно один (соответствующий) элемент. То есть, когда имеется ноль или более одного предмета.
Когда следует использовать Single
?
Использование Single
целесообразно, когда логика вашей программы может гарантировать, что коллекция даст только один элемент и только один элемент. Если возникает исключение, это должно означать, что логика вашей программы содержит ошибку.
Если вы обрабатываете «ненадежные» коллекции, такие как ввод-вывод, вы должны сначала проверить ввод, прежде чем передать его в Single
. Single
вместе с блоком catch
исключения не подходит для того, чтобы убедиться, что в коллекции есть только один соответствующий элемент. К тому времени, когда вы вызываете Single
, вы должны уже убедиться, что будет только один соответствующий элемент.
Вывод:
Выше изложено мое понимание оператора Single
LINQ. Если вы последуете этому соглашению и согласны с ним, вы должны прийти к выводу, что Single
должен вызвать исключение как можно раньше . Нет причин ждать до конца (возможно, очень большого) набора, потому что предварительное условие Single
нарушается, как только он обнаруживает второй (соответствующий) элемент в коллекции.