Search
Close this search box.

C#/.NET Little Wonders: First() and Single() – Similar Yet Different

Once again, in this series of posts I look at the parts of the .NET Framework that may seem trivial, but can really help improve your code by making it easier to write and maintain.

Today we’re going to look at two LINQ extension methods that are both very similar and yet very different.  Logically, First() and Single() serve similar purposes, but there is a subtle difference between these two that if you aren’t expecting it may give you very different behaviors.

First() – Retrieves the first occurrence

The First() method, as its name implies, finds the first item in a sequence.  Now, there are actually four flavors of this method, each with their own twist.  Each of these are extensions methods that operate on any IEnumerable<TSource>:

  • First()
    • Returns the very first item in the sequence, if no item exists throws InvalidOperationException.
  • First(Func<TSource, bool>)
    • Returns the very first item in the sequence that matches the predicate, if no item exists that matches throws InvalidOperationException.
  • FirstOrDefault()
    • Returns the very first item in the sequence, if the sequence is empty returns default(TSource).
  • FirstOrDefault(Func<TSource, bool>)
    • Returns the very first item in the sequence that matches the predicate, if no item exists that matches returns default(TSource).

The first thing of note is that the First() method returns the first item (or first match in the case of the predicate version).  This means if there is more than one item in the list (or more than one match) only the first item is returned.  This also means that the moment the first item is found, the method exits immediately and does not scan the remainder of the enumerable.

Let’s take a look at how this behaves.  For the purposes of this illustration let’s assume we have this POCO defined:

1 : public sealed class Employee 2 : {
  3 : public long Id {
    get;
    set;
  }
  4 : public string Name {
    get;
    set;
  }
  5 : public double Salary {
    get;
    set;
  }
  6:
}

And that we’ve loaded up three lists for illustrative purposes.  One with no elements, one with one element, and one with many elements:

1 :  // empty
     2 : var noEmployeeList = new List<Employee>();
3 : 4 :  // one item
         5 : var oneEmployeeList = new List<Employee> 6
    : {
      7 : new Employee{Id = 55, Name = "Sussie Queue", Salary = 60000.50} 8 :
    };
9 : 10 :  // many items
          11 : var employees = new List<Employee> 12 : {
            13 : new Employee{Id = 1, Name = "Jim Smith", Salary = 12345.50},
            14 : new Employee{Id = 7, Name = "Jane Doe", Salary = 31234.50},
            15 : new Employee{Id = 9, Name = "John Doe", Salary = 13923.99},
            16 : new Employee{Id = 13, Name = "Jim Smith", Salary = 30123.49},
            17 :  // ... etc ...
                18 :
          };

Now, if we apply our First() methods to this, we can see how it will behave.  In both cases, the method will return the first item they are looking for regardless of how many items (or match duplicates) the list may contain.

1 :  // gets the first Jim Smith with Id of 1
     2 : var first = employees.First();
3 : 4 :  // gets the first employee whose name starts with John.
         5 : var firstJohn = employees.First(e = > e.Name.StartsWith("John"));
6 : 7 :  // gets the first employee whose name ends with Doe, even though there
         // are
         8 :  // many, in this case it gets Jane Doe, Id = 7
              9 : var firstDoe = employee.First(e = > e.Name.EndsWith("Doe"));

The second thing to notice is that the two First() method overloads will throw if no items exist (or no matches exist in the predicate version):

1 :  // throws at runtime because empty enumerable.
     2 : var empty = noEmployees.First();
3 : 4
    :  // this line will throw at runtime because there is no item that matches
       5 :  // even though the enumerable itself is not empty
            6 : var noMatch = employees.First(e = > e.Id == 20);

And then finally, notice that the two FirstOrDefault() methods behave similarly to their First() counterparts in that they return the first match, but instead of throwing an InvalidOperationException they will instead return the default(TSource) if no items exist (or no matches exist in the predicate version).  Now, remember that the default operator will return the default value for any type.  For numerics this is zero, for bool this is false, for reference types this is null, etc.

1 :  // instead of throwing, this returns default(Employee) which is null
     2 : var empty = noEmployees.FirstOrDefault();
3 : 4 :  // this also returns null since no match exists
         5 : var noMatch = employees.FirstOrDefault(e => e.Id == 20);

Single() – Returns the one and only occurrence

So now that we’ve seen how First() and its cousin works, let’s look at Single().  Just like First()Single() scans an enumerable looking either for the first item or the first match — however, that’s where the similarity ends!  Remember that First() only cares about the first item it finds and ignores any other items or matches.  Single() on the other hand will throw an InvalidOperationException if it is not the only item (or match) in the list!

The overloads for Single() and its cousin SingleOrDefault() are very similar to First() and FirstOrDefault():

  • Single()
    • Returns the only item in the sequence, if no item exists throws InvalidOperationException, and if more than one item exists, also throws InvalidOperationException.
  • Single(Func<TSource, bool>)
    • Returns the only item in the sequence that matches the predicate, if no item exists that matches throws InvalidOperationException, and if more than one item exists that matches the predicate, also throws InvalidOperationException.
  • SingleOrDefault()
    • Returns the only item in the sequence, if the sequence is empty returns default(TSource), but if more than one item exists throws InvalidOperationException.
  • SingleOrDefault(Func<TSource, bool>)
    • Returns the only item in the sequence that matches the predicate, if no items match predicate returns default(TSource), or if more than one item matches throws InvalidOperationException.

Notice the main key difference here between the Single family and the First family is that if there is more than one item (or match) in the list it will always throw InvalidOperationException.  Also notice that this means that even if the form of Single() that takes a predicate finds its match early on, it still potentially has to scan up to the remainder of the enumerable to make sure there wasn’t a duplicate.  This can make Single() a bit less efficient if you have other ways of assuring that you won’t have duplicates in the enumerable.

1 :  // gets the one and only item from the list (Sussie Queue)
     2 : var oneAndOnly = oneEmployeeList.Single();
3 : 4 :  // throws because not exactly one item in list.
         5 : var throwsOnEmpty = noEmployeeList.Single();
6 : 7 :  // throws because more than one item in list.
         8 : var throwsOnMultiple = employeeList.Single();

Also notice that in the version that takes a predicate a similar rule holds true where it will behave like the predicate version of First() except if there is more than one match it will throw the InvalidOperationException:

1 :  // gets the one and only item from the list with ID == 7
     2 : var oneAndOnlyMatch = oneEmployeeList.Single(e => e.Id == 7);
3 : 4 :  // throws because there are no matches
         5 : var throwsOnNoMatches = noEmployeeList.Single(e => e.Id == 999);
6 : 7 :  // throws because there are multiple matches
         8 : var throwsOnMultipleMatches =
                 employeeList.Single(e => e.Name.EndsWith("Doe"));

Finally, just like with FirstOrDefault()SingleOrDefault() will return a default(TSource) if no items (or no matches) are found:

1 :  // now, instead of throwing provides a default for the type (null for
     // reference types) if empty.
     2 : var defaultsOnEmpty = noEmployeeList.SingleOrDefault();
3 : 4 :  // now, instead of throwing provides a default for the type (null for
         // reference types) if no match.
         5 : var defaultsOnNoMatch =
                 noEmployeeList.SingleOrDefault(e => e.Id == 999);

Summary – when to use each?

So here we saw two similar, yet different, classes of extension methods to get the first (or first matching) item in a list. The main difference being that the First() family looks for the first item (or match) then stops and ignores other matches, whereas the Single() family looks for the one and only item (or match) and if it finds multiple it will throw an exception.

Both have the option of removing the exception when no item (or match) is found with the …OrDefault() versions, but Single() will always throw if there are duplicates, by design (because if you didn’t want it to obviously you’d use First()).

So my general advice on using these two very handy method families is to use the First() family when you either don’t care about duplicates or are reasonably sure through other means (like it comes from a database table with a primary key constraint) that there are no duplicates.

Single is handy if you need to verify an enumerable and want to ensure no duplicates when you don’t have direct control over the integrity of the original data, but keep in mind that means that any call to the predicate version of Single() may potentially search the whole list to check for a duplicate where the predicate version of First() will just stop on the first match.

Finally, if you aren’t sure if an item exists, favor the …OrDefault() flavors of these two method families, though these are typically more useful for enumerables of reference types, since null is a good indicator nothing was found, whereas if you search an enumerable of int and it’s not found, it will return 0 which is also possibly a valid value in the enumerable.

Print | posted on Thursday, April 14, 2011 7:09 PM | Filed Under [ My BlogC#Software.NETLittle Wonders ]

This article is part of the GWB Archives. Original Author: James Michael Hare

Related Posts