James Michael Hare

...hare-brained ideas from the realm of software development...
posts - 137 , comments - 1100 , trackbacks - 0

My Links

News

Welcome to my blog! I'm a Sr. Software Development Engineer in Seattle, WA. I've been doing C++/C#/Java development for over 18 years, but have definitely learned that there is always more to learn!

All thoughts and opinions expressed in my blog and my comments are my own and do not represent the thoughts of my employer.

Blogs I Read

MCC Logo MVP Logo

Follow BlkRabbitCoder on Twitter

Tag Cloud

Archives

Post Categories

C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count() Extension Methods

Once again, in this series of posts I look at the parts of the .NET Framework that may seem trivial, but can help improve your code by making it easier to write and maintain. The index of all my past little wonders post can be found here.

On this post I will finish examining the System.Linq methods in the static class Enumerable by examining two extension methods Count() and DefaultIfEmpty(), and one static method Empty().

The Empty() static method

How many times have you had to return an empty collection from a method (either due to an error condition, or no items exist, etc.) and created an empty array or list?

Let’s look at a simple POCO to hold transfers between two bank accounts:

   1:  public class Transfer
   2:  {
   3:      public string FromAccount { get; set; }
   4:      public string ToAccount { get; set; }
   5:      public double Amount { get; set; }
   6:  }

 

Now let’s say we have a data access object that is supposed to grab the outstanding transfers and return them.  However, if the transfer service is down for maintenance, we just want to return an empty sequence of transfers.

We could of course return null, but returning the empty sequence is generally preferable than returning null.  So we’ll return an empty sequence in the form of a list (or array would do as well):

   1:  public class TransferDao
   2:  {
   3:      public IEnumerable<Transfer> GetPendingTransfers()
   4:      {
   5:          if (!_txfrService.IsInMaintenanceMode())
   6:          {
   7:              // create a list of transfers and return it...
   8:          }
   9:   
  10:          // otherwise, since we're in maintenance mode, return an empty collection:
  11:          return new List<Transfer>(0);
  12:      }
  13:  }

 

The problem with this is that we are essentially wasting a memory allocation for something that will never change.  If all we intend to do is return a read-only empty sequence of a given type, we can use LINQ’s empty sequence singleton factory to represent it and not waste a memory allocation every time:

   1:  public class TransferDao
   2:  {
   3:      public IEnumerable<Transfer> GetPendingTransfers()
   4:      {
   5:          if (!_txfrService.IsInMaintenanceMode())
   6:          {
   7:              // create a list of transfers and return it...
   8:          }
   9:   
  10:          // otherwise, since we're in maintenance mode, return an empty collection:
  11:          return Enumerable.Empty<Transfer>();
  12:      }
  13:  }
 

Note that we’re calling the Empty<T>() static method off of the Enumerable class, this is the same class where all the extension methods for IEnumerable<T> are defined, but Empty is actually just a simple static method which returns a singleton empty sequence for type T. 

The DefaultIfEmpty() extension method

So we’ve seen that the static Empty<T>() method can be used to generate singleton, read-only empty sequences of type T.  But what happens if you want to return a sequence containing a single default item if a sequence is empty?

Why would you ever want to do this, you say?  Well, for example what if you’re analyzing a list of test scores, but want to return a single scores of zero if the student has no scores so far:

   1:          var scores = new[] { 73, 77, 89, 90, 92, 77 };
   2:   
   3:          // If scores is non-empty, returns that sequence, if scores is empty, returns
   4:          // a sequence with a single item which is default(int) in this case (0).
   5:          foreach (var score in scores.DefaultIfEmpty())
   6:          {
   7:              Console.WriteLine("The score is: " + score);
   8:          }

 

Now, there is also a second form of DefaultIfEmpty() that lets you specify the default to use if the sequence is empty instead of relying on default(T) where T is the type held by the IEnumerable<T> sequence.  For example, what if we want an average of all the scores, but want to return an average of 100 if no scores have been entered yet?

   1:  // will average the sequence if it's not empty, or if it is empty, will
   2:  // return 100 - or more precisely in this case, the average of a sequence 
   3:  // containing just 100
   4:  var averageSoFar = scores.DefaultIfEmpty(100).Average();

 

Note that if you don’t specify the default value, it uses the default(T), which is the default value for type Tnull for reference types, zero for numeric, etc.

The Count() extension method

This may seem like a no-brainer, right?  The Count() method returns the number of the items in the sequence, correct?  Yes, for the most part, but it also has some nice features worth mentioning.

First of all, calling Count() with no arguments (aside from the implicit source in the extension method syntax) returns the count of the sequence as you’d expect.  This may seem somewhat redundant for types like List<T> which maintains a Count already, or arrays that contain a Length property:

   1:  var scoreArray = new[] { 73, 77, 89, 90, 92, 77 };
   2:  var scoreList = new List<int> { 73, 77, 89, 90, 92, 77 };
   3:   
   4:  // get count of array using Length property and the Count() extension method:
   5:  Console.WriteLine(scoreArray.Length);
   6:  Console.WriteLine(scoreArray.Count());
   7:   
   8:  // get count of list using Count property and the Count() extension method:
   9:  Console.WriteLine(scoreList.Count);
  10:  Console.WriteLine(scoreList.Count());

 

Note that (if we are using the System.Linq namespace) the list has both the Count property defined in the List<T> class, and the Count() extension method defined on IEnumerable<T>.  This may seem redundant, but keep in mind that not all IEnumerable<T> implementations have a count defined, so the only way to find out the count of those sequences is to count them.  In addition, this ensures that for any IEnumerable<T> there is a consistent method that can be called to get the count of the sequence.

Now, you may think that this is a big red flag, and that for List and arrays the Count() extension method would be an O(n) – linear – operation if it had to count all the items in the list, whereas Count and Length are O(1) – constant-time – operations.  Fear not, however, the Count() extension method first checks to see if the type implementing IEnumerable<T> also implements ICollection<T> or ICollection (non-generic) as well.

Why is this important?  Because any collection that implements ICollection or ICollection<T> must specify a Count property.  Since List<T>, arrays, and many other collections implement ICollection<T>, this means the Count() extension method can cast them and call Count directly and avoid having to count the items.

Thus, calling Count() extension method on a list is slightly less efficient than calling Count property because it has to check the type and cast, but it’s still a constant-time – O(1) – operation.  And, the nice thing is this means you can call Count() extension method on any IEnumerable<T> sequence for consistency and know that it will make the right choice for efficiency.

So, simple Count(), not very exciting eh?  Well, Count() has an overload which takes a predicate (Func<T, bool>) which allows you to count all items in the sequence that meet the predicate condition:

   1:  var scoreList = new List<int> { 73, 77, 89, 90, 92, 77 };
   2:   
   3:  var numberOfBsOrBetter = scoreList.Count(s => s >= 80);

 

Once again this works for any sequence of IEnumerable<T> and is a very handy shortcut for:

   1:  // why type this when there's a handy count overload!
   2:  var numberOfBsOrBetter = scoreList.Where(s => s >= 80).Count();

 

So in addition to counting all items, this form of count is very handy for counting only the items in a collection that meet any given condition.

A side note on Count() versus Any()

The Count() extension method is very useful for checking for the number of items in a sequence, but if all you really want to know is if a sequence is non-empty, it’s probably more efficient to use the Any() extension method instead, because the Any() method halts as soon as it finds the first item that meets the criteria, instead of counting all items that meet the criteria:

   1:  // this counts all the items even if the first item is already a match
   2:  var hasAnyBsOrBetter = scoreList.Count(s => s >= 80) != 0;
   3:   
   4:  // do this instead, it will halt on the first match and not check further
   5:  var hasAnyBsOrBetter2 = scoreList.Any(s => s >= 80);

 

Note that Any(), like Count() can be called with no parameters (besides the implicit extension method source parameter) which tells you if the list contains any item at all (that is, if it’s not empty:

   1:  // this counts all the items in the sequence even if we only care about non-empty:
   2:  var isEmpty = someSequence.Count() == 0;
   3:   
   4:  // this only checks to make sure there is at least one item and stops
   5:  var isEmpty2 = !someSequence.Any();

 

If the sequence is something like a list or array it may not matter because they have a constant time – O(1) – count implementation, but for other sequences, it’s much more efficient to check Any() for non-empty, since Any() will halt after the first find. 

In addition there is no performance short-cut on Count() with the predicate, so if you only care that there’s at least one match and not how many, Any() is again the better choice.

Summary

These are the last of the Enumerable methods I’ve been working through as part of my Little Wonders series.  The Empty() static method is useful for using a singleton to represent an empty sequence of a type instead of creating empty collections which need to be garbage collected.  The DefaultOrEmpty() is useful if you want to have a single default value stand in for an empty sequence.  Finally, the Count() extension method is handy for counting either items in a sequence, or items in a sequence that match a given predicate.

Hope you’ve enjoyed the Little Wonders of the Enumerable static class, there are plenty more wonders to be seen in other areas so stay tuned!

  

Print | posted on Thursday, June 2, 2011 7:08 PM | Filed Under [ My Blog C# Software .NET Little Wonders ]

Feedback

Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

Hi James
Just wanted to say I've really got a lot from this series so far - thank you. Please keep it going!
6/3/2011 6:40 AM | James Munro
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

@James: Thanks so much for the compliment! Will do!
6/3/2011 8:35 AM | James Michael Hare
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

This series is always so helpful. Thank you!
6/3/2011 11:29 AM | Jesse Williamson
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

Thanks for introducing Enumerable.Empty<T>()! I did not know that one ...
As James already said, please keep up the great work!
6/3/2011 12:21 PM | Marius Schulz
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

Great post, these are some cool gems to remember when using lists and arrays. I really like the "side note", it's nice to see the cost/benefits of making one choice over another. Knowing that Any() stops on the first hit, could definitely result in some big time savings. Thanks.
6/28/2011 1:46 AM | Zachary Hunter
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

Found this article from random rss feeds.
Very helpful.
Starting to read the whole series.

Thanks!
6/28/2011 2:58 AM | mshsayem
Gravatar

# Great Summary!

James, this was a great summary, and thanks for pointing out the fact that Count() will call the most efficient implementation, and the short-circuit evaluation of Any() with a predicate. This is behavior I just assumed, but it's glad to know that it's being done right! Thanks for the write-up.
6/28/2011 6:23 PM | Ethan Brown
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

Excellent series. Clear and concise explanations and examples. Good work!
6/29/2011 2:16 AM | Phil Cole
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

Nice series. Helpful to sharp my skills!! Thanks
7/11/2011 1:08 AM | NCV
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

The call to Enumerable.Empty<Transfer>(); is preferable to new List<Transfer>(0), but if your code is really intensive, you might want to use a previously initialized static empty array.

Also, there's no memory barrier in Enumerable.Empty<Transfer>() so it is possible that it will return null instead of an empty array if used on certain classes of multi-core and / or multi-processor machines.
8/2/2011 9:57 AM | D15724c710n
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

@D15724c710n:

I'd say you'd want to prefer Enumerable.Empty<Transfer>() as you say, because it avoids the needless allocations. However, if you wanted to "cache" your empty value somewhere, you could still do it just as easily in an initializer using Empty:

private static readonly IEnumerable<string> EmptyStringList = Enumberalbe.Empty<string>();

Though really either way is fine, at that point it becomes a matter of preference.

I'll have to dig into the memory barrier comment and see what I can see.
8/2/2011 1:01 PM | James Michael Hare
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

On Enumerable, the MSDN does declare that: "Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe."

Which should apply to Empty() as well. I don't see any synchronization primitives in the decompiled code, so not sure if they are accepting possible duplication in the case multiple catch the null at the same time, or something.

I'm not sure how I could see that method ever returning null though, can you elaborate?
8/2/2011 1:08 PM | James Michael Hare
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

I've tried to elaborate a couple of times now, but because I enter urls (to ms blogs), my comment doesn't get posted :-)
8/5/2011 8:51 AM | D15724c710n
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

Sorry about that, it's our spam comment filter. Without it we have a ton of obviously spam comments.

Can you click on the contact me and send me the links directly?
8/5/2011 2:09 PM | James Michael Hare
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

@D15724c710n: Enumerable.Empty<Transfer>() doesn't need a memory barrier because it doesn't guarantee that it will always return the same object. It will never return null. If there are concurrent calls, multiple empty objects may be created, the last of which will replace any prior saved objects in the internal static field.
8/18/2011 9:49 AM | Ed Brey
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

Using Enumerable.Empty<TResult> causes a there to be a new root object that must be walked during garbage collection. This object stays around for the life of the appdomain. For cases where the empty collections are rarely created, it seems overall performance may be better in the long run if you just used "new".
8/18/2011 9:56 AM | Ed Brey
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

@Ed: That's what I was thinking on the memory barrier as well, I was hoping D15724c710n could clarify since I couldn't see the issue he was presenting.

Interesting note on the Empty. However since only one is held for the life of the app domain (per type), this doesn't really seem like an issue since it would be promoted to gen 3 of the GC eventually and not get checked very often.
8/18/2011 2:20 PM | James Michael Hare
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

really great article. One thing I will def use is Any() instead of Count() wherever applicable. Keep up the good work mate.
8/23/2011 10:45 PM | Nimesh
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count()

@Nimesh: Thanks!
8/24/2011 8:34 AM | James Michael Hare
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count() Extension Methods

"the Any() method has the same short-cuts for ICollection and ICollection<T>"

Did you mean "the same short-cuts as Count()" ?
Because I decompiled my System.Core.dll to see how Any() is implemented and I see no optimization. It just checks if the MoveNext() call on the enumerator performs correctly. I see no specific code for ICollection.
11/21/2011 4:51 AM | KG
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count() Extension Methods

@KG: Odd, I was trying to rethink what I was thinking when I wrote that, I wonder if I meant the same complexity, but then not sure why I'd mention ICollection<T>, at any rate, it's an error on my part, I'll fix it.

Thanks for the heads up!
11/21/2011 9:35 AM | James Michael Hare
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count() Extension Methods

In the article in the third code example you have "return Enumerable.Empty>();" which gives me an error in VS saying "expression expected". Doesn't one have to specify the type in between the angle brackets like "return Enumerable.Empty<Transfer>();" ?
1/14/2014 10:12 AM | Joe
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count() Extension Methods

I posted in the previous comment "return Enumerable.Empty anglebracket Transfer anglebracket();" I guess the angle brackets are getting lost in the html parser or something.
1/14/2014 10:14 AM | Joe
Gravatar

# re: C#/.NET Little Wonders: Empty(), DefaultIfEmpty(), and Count() Extension Methods

Really Nice Diff. ................
Thanks a lot
5/23/2014 11:26 PM | Vivek Singh
Post A Comment
Title:
Name:
Email:
Comment:
Verification:
 

Powered by: