Mark Needham

Thoughts on Software Development

Functional Collection Parameters: Handling the null collection

with 5 comments

One of the interesting cases where I've noticed we tend to avoid functional collection parameters in our code base is when there's the possibility of the collection being null.

The code is on the boundary of our application's interaction with another service so it is actually a valid scenario that we could receive a null collection.

When using extension methods, although we wouldn't get a null pointer exception by calling one on a null collection, we would get a 'source is null' exception when the expression is evaluated so we need to protect ourself against this.

As a result of defending against this scenario we have quite a lot of code that looks like this:

public IEnumerable<Foo> MapFooMessages(IEnumerable<FooMessage> fooMessages)
{
	var result = new List<Foo>();
	if(fooMessagaes != null)
	{
		foreach(var fooMessage in fooMessages)
		{
			result.Add(new Foo(fooMessage));
		}
	}
	return result;
}

The method that we want to apply here is 'Select' and even though we can't just apply that directly to the collection we can still make use of it.

private IEnumerable<Foo> MapFooMessages(IEnumerable<FooMessage> fooMessages)
{
	if(fooMessages == null) return new List<Foo>();
	return fooMessages.Select(eachFooMessage => new Foo(eachFooMessage));
}

There's still duplication doing it this way though so I pulled it up into a 'SafeSelect' extension method:

public static class ICollectionExtensions
{
       public static IEnumerable<TResult> SafeSelect<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
       {
               return source == null ? new List<TResult>() : source.Select(selector) ;
       }
}

We can then make use of this extension method like so:

private IEnumerable<Foo> MapFooMessages(IEnumerable<FooMessage> fooMessages)
{
	return fooMessages.SafeSelect(eachFooMessage => new Foo(fooMessage));
}

The extension method is a bit different to the original way that we did this as I'm not explicitly converting the result into a list at the end which means that it will only be evaluated when the data is actually needed.

In this particular case I don't think that decision will have a big impact but it's something interesting to keep in mind.

Written by Mark Needham

June 16th, 2009 at 8:29 pm

5 Responses to 'Functional Collection Parameters: Handling the null collection'

Subscribe to comments with RSS or TrackBack to 'Functional Collection Parameters: Handling the null collection'.

  1. Another way around this is an extension method to IEnumerable that will pass through non-null source and return Enumerable.Empty() for a null source:

    IEnumerable EmptyIfNull(this IEnumerable source)
    {
    if (source == null)
    return Enumerable.Empty();

    return source;
    }

    Then your function can look like this:

    private IEnumerable MapFooMessages(IEnumerable fooMessages)
    {
    return
    fooMessages
    .EmptyIfNull()
    .Select(eachFooMessage => new Foo(fooMessage));
    }

    Chris Ammerman

    17 Jun 09 at 1:45 am

  2. Arg, all my generics got dropped by the sanitizer….

    I also forgot to note that the EmptyIfNull approach is really nice because then all of the non-aggregatory IEnumerable operations will automatically work because they all know how to handle an empty collection! So, just one function to enable all operations, instead of one for each.

    Chris Ammerman

    17 Jun 09 at 1:48 am

  3. That's a pretty neat idea, hadn't thought of that. I guess that also has the benefit of making it more obvious what's going on

    Mark Needham

    17 Jun 09 at 7:33 am

  4. I can't remember if you've written about the null-coalescing operator '??', but I've been using it a lot to remove all those annoying 'if (x == null)'s

    return (source ?? new List() ).Select(selector) ;

    Iain B

    17 Jun 09 at 8:04 pm

  5. [...] written previously about the ways I've been making use of functional collection parameters in my code but what I hadn't really considered was that the way of thinking [...]

Leave a Reply