views:

254

answers:

8

I'm getting tired of using code like this:

var count = 0;
if (myEnumerable != null)
{
    count = myEnumerable.Count();
}

And this is a bit pedantic:

var count = (myEnumerable ?? new string[0]).Count();

Is there any tidier way of doing this? I once had a (badly named) PhantomCount extension method on IEnumerable<> that used my first code example, but it had something of a smell about it (besides the name).

+8  A: 

How about

count = myEnumerable == null? 0 : myEnumerable.Count()
erash
I have a feeling that hes going to ask for a tidier than this, +1 none the less :)
VoodooChild
Your feeling is correct, but it's a good answer anyway.
ProfK
+23  A: 

The problem is really in whatever is creating these enumerables. Unless you have a really good reason, anything that generates an iterable collection should return an empty collection instead of null. This would align with the Null-Object-Pattern, hence the benefits are the same.

My suggestion would be to fix whatever produces myEnumerable, or if you can't do this, add a check way earlier to see if it's null and react appropriately.

Anon.
+1 for diagnosing the root cause
erash
Have another +1. It is really good practise when designing an API to return empty collections rather than nulls to avoid placing a burden on developers to do testing like this all the time.
uriDium
Depends. There is a difference between the list of all the really good wines made in Ireland (which is an empty list) and all the really good wines made in Narnia (which is null, because Narnia doesn't exist). Sometimes it is necessary to distinguish null from empty. I do agree that one should lean toward the returning empty though.
Jon Hanna
@Jon: Using null to signal a special condition is like an automobile applying the handbrake to indicate that it's low on gas.
Anon.
@Anon Using null to signal a null condition is like, eh, something really obvious and straight-forward and sensible.
Jon Hanna
These days, the null object pattern is quite often considered dangerous/bad practice - for good reason. Use with care.
Noldorin
@Jon Hanna, I agree that null is a good indicator of an invalid enumerable state, though generally you'd probably want to throw an exception rather than indicate invalid state. That said, it definitely seems wrong to me to treat a null enumerable as if it were empty; I would probably create adapter methods around the offending class that compensate for the deficiency so that the client code is insulated from it. It's more code to write a separate adapter for each flawed method, but it keeps the client code cleaner.
Dan Bryant
@Dan. I disagree, I don't think null is a good indicator of an invalid state. It's a good indicator when "enumerable does not exist" and "enumerable exists and is empty" are both valid and may be purposefully distinguished. When they are both valid but of no practical difference, then an empty enumerable in the null-object pattern rocks (a favourite of mine), and when one isn't valid, I'd throw an exception. All three cases can happen in reasonable well thought-out code.
Jon Hanna
Thanks guys for the all nutritional comments. This is inspiration for a blog post, and credit will be given.
ProfK
+9  A: 

I don't think using extension method is a bad idea.

public static int NullableCount<T>(this IEnumerable<T> collection)
{
   return collection == null ? 0 : collection.Count();
}
Danny Chen
+1 I made exactly the same thing - just named it `CountOrZero`. I personally think it is clearer.
lasseespeholt
+2  A: 

Just create your own extension method that handles null enumerables as you wish.

public int CountOrNull<T>(this IEnumerable<T> source)
{
    return source == null ? 0 : source.Count();
}

You can then simply use:

var list1 = new int[] { 1, 2, 3, 4 };
var list2 = (int[])null;

var count1 = list1.CountOrNull(); // 4
var count2 = list2.CountOrNull(); // 0

That's the great thing about extension methods. They still work fine even if the object on which (you appear to be) calling the method is null.

Noldorin
_@Noldorin:_ Fixed a typo in your code example (the `// 4` comment); perhaps verify that this is indeed what you intended.
stakx
@stakx: Thanks; it was indeed a typo.
Noldorin
+2  A: 

I would also write my own extension method CountOrZeroForNull, as shown in other answers.

Besides... Instead of:

var count = (myEnumerable ?? new string[0]).Count();
                          // ^^^^^^^^^^^^^

you could write:

var count = (myEnumerable ?? Enumerable.Empty<string>()).Count();
                          // ^^^^^^^^^^^^^^^^^^^^^^^^^^

This doesn't alleviate your specific problem, but it circumvents allocation of an unused array. (Enumerable.Empty<T> is most likely implemented as a simple yield break statement.)

stakx
The current implementation of `Enumerable.Empty<T>` actually returns a singleton empty `T[]` array.
LukeH
_@LukeH:_ I wouldn't have thought that. Thanks for looking this up.
stakx
A: 
var count = 0; 

if (myEnumerable != null) 
    count = myEnumerable.Count(); 

While it's not as technical as the other answers, it's far the most readable.

SLC
I don't think those three lines are more readable than a well-named extension method.
Lee
Yes, I want to avoid repeating the same check several times. That was the point of my question after all.
ProfK
Heh, maybe read the question?
Jaco Pretorius
+1  A: 

What actions are you taking if the value returned is 0?

If that's what's interesting, maybe you should use Haack's IsNullOrEmpty extension method for IEnumerable like so:

public static bool IsNullOrEmpty<T>(this IEnumerable<T> items) 
{
    return items == null || !items.Any();
}

The link is http://haacked.com/archive/2010/06/10/checking-for-empty-enumerations.aspx

Posted as a comment on the blog, you'll also find an Exception class I wrote to go with that:

public class ArgumentNullOrEmptyException : ArgumentNullException
{
    public ArgumentNullOrEmptyException( string paramName ) : base( paramName )
    {}

    public ArgumentNullOrEmptyException( string paramName, string message ) : base( paramName, message )
    {}

    public override string Message
    {
        get
        {
            return "Value cannot be null nor empty.{0}Parameter name: {1}".FormatWith( Environment.NewLine, ParamName );
        }
    }
}
Martin R-L
+5  A: 

I use a custom extension method:

public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source)
{
    return source ?? Enumerable.Empty<T>();
}

...

int count = myEnumerable.EmptyIfNull().Count();
Thomas Levesque
+1, I think this is the cleanest of the extension method solutions listed. It's very explicit that you're assuming a null enumerable to simply be empty, after which you can work with the enumerable as usual.
Dan Bryant