The purpose of the
Single extension methods is to thrown an exception if more than one item matches the query (or, in the parameterless implementation, more than one item exists in the enumerable). It seems obvious then that the method should stop enumerating once finding the second match, throwing the appropriate exception. And indeed this is how the parameterless implementation behaves.
The code in this first example calls
Enumerator.MoveNext() twice. Once for the matching result, and once to find that a second result exists, throwing the
However, the code in this second example calls
Enumerator.MoveNext() 10 times, once for each element in the source enumerable. It counts the number of matches and then still simply throws the
exception if more than one match exists.
Enumerable.Range(1,10).Single(x => x < 5)
The counting of the matches is useless, and therein lies the performance problem. If there were many items in the source
IEnumerable or enumerating the source incurred a performance penalty, it is a waste of time and resources to continue enumerating past the second matching item. Once it is determined there is more than one match, enumeration should cease and the exception should be thrown.
The simple solution to this problem is to change the
Single method to the Where method with a
Single method hanging on the end. This combines the
Where filter with the proper behavior of the parameterless
Enumerable.Range(1,10).Where(x => x < 5).Single()