Continuing on my path to LINQ greatness, I want to cover another topic that some people get confused over: LINQ’s First() vs. Single(). Both perform a particular task for us, but just by looking at the name you’d never know which one performed the action that you expected.
- First() returns the first element in a sequence …
- Single() returns the _only_ occurrence of the element in the sequence …
… Beware: They Throw Exceptions
One _very_important_ thing to be aware of is that these two functions throw exceptions if they do not find what they are looking for. First() will throw if it cannot find the first matching value, Single() will throw if it cannot find the value and if there are more than one matching element in the input sequence. Therefore they have sister functions called FirstOrDefault() and SingleOrDefault().
The FirstOrDefault() method will search for an element in the sequence and if the first requested element is not found (that matches the functor) the function will return the default value (usually null if a reference type).
The SingleOrDefault() method will search for a single occurrence of the requested element that matches the functor. If the element is not found it will return the default value (usually null if a reference type), OR if the method finds more than 1 result matching the functor this method will throw an InvalidOperationException. The reason this method will throw is because the input sequence contains more than one matching element. Single follows the “one” and “only one” return mechanism. If more than one element matches your predicate, this method will throw.
All the combinations of throw/success can get kind of confusing and is best illustrated with a simple table.
First vs Default Success/Throw Matrix
Method | Success When … | Throws When … |
First() | 1..* – elements match | 0 elements match |
FirstOrDefault() | 0..* – elements match | (does not throw) |
Single() | 1..1 – one element matches | 0 | >1 – elements match |
SingleOrDefault() | 0..1 – Elements match | >1 – elements match |
Conclusion
The end goal here is to be aware of what you’re doing with LINQ. All in all, be careful.
If you use “First” be aware that it WILL thrown an exception if the element is not found. This can be a simple mistake. Example – while unit testing you may set up a List<Orders> to use for testing. You ensure your code works for valid orders but perhaps you forgot to test the code with an empty list. Doing this would have caught your error because the First() method would have told you right away by throwing exception.
Think about how you want to handle your use cases. With a null, or an exception handling routine? It’s up to you as null/exception handling is a different debate all together. I hope this helped some of you out there.
Maran says
Good article.. Thanks
Latency McLaughlin says
This was great! Love the matrix.