Saturday, February 2, 2008

Using C# 3.0 Extension methods and Lambda expressions to avoid nasty Null Checks

In the project I am currently working on we use a domain model with a quite deep nested structure of classes, code like the following is quite common.
// do something with the Adress
Console.Writeline(Contract.Parties.Client.Adress.Street);

The problem with this is that not all Contacts have a related Parties object and if we do have a Parties object sometimes the Client object is Null. This lead to writing a lot of code code like the following:
if (Conract != Null &&
    Contract.Parties != null &&
    Contract.Parties.Client != null &&
    Contract.Parties.Client.Adress != null)
{
    // do something with the Adress
    Console.Writeline(Contract.Parties.Client.Adress.Street);
}

There are a few problems with this code, the first of which is that it is quit verbose. Second it evaluates the same properties over and over again. In order to reduce the double work we could introduce some extra local variables and create a separete if statement for every step, this will make it even more verbose than it is allready.
Of course C# 3.0 has a lot of new syntax tricks, like extension methods, lambda expression and type inference. I had seen some nice examples (mostly Linq related) but had not been using these features to the max myself. Somehow I got the idea that these features would help me solve the Null checking problem.
I figured that the code I wanted to write was something like the following.
if (Contract
    .NullSafe(c => c.Parties)
    .NullSafe(p => p.Client)
    .NullSafe(c => c.Address) != null)
{
    // do something with the adress
    Console.Writeline(Contract.Parties.Client.Adress.Street);
}

The idea is that all parts of the path are expressed in separate lambda expressions which are chained together. If any link in the chain returns null, the rest of the path is never evaluated and the result of the whole expression will also be null.
All I had to do to make this possible was write one single extension method that would operate on any object, I was quite amazed that I could do this with verry little code that, besides some generic stuff, was actually quite simple.
        public static TResult NullSafe(this T target, Func func)
        {
            if (target != null)
                return func(target);
            else
                return default(TResult);
        }

All the generics make it look a lot more complicated than it actually is. This extension method receives two arguments, the first of which is the object it operates on and the second is a generic Func delegate (the lambda expression). The return type of the extension method is automatically inferred from the return type of the lambda that is passed in. This allows you to call NullSafe again on the result of the first call and use IntelliSense to type p.Client in the second lambda.
The nice thing about extension methods is, besides that they can operate on any existing class without changing it, that they can also operate on Null references without causing a NullReferenceException!! This makes it possible to test for null inside the extension method. If the object it is called on is not null it evaluates the lambda expression and returns the result. Otherwise it returns the default value of the expected return type, for reference types this is Null.
To make life even better I created another overload of NullSafe that was even simpler

        public static void NullSafe(this T target, Action action)
        {
            if (target != null)
                action(target);
        }

Instead of a generic Func delegate this one receives a Generic Action delegate and returns void.
This removes the need to retype the whole path inside the if, it actually removes the if altogether.

Contract
    .NullSafe(c => c.Parties)
    .NullSafe(p => p.Client)
    .NullSafe(c => c.Address)
    .NullSafe(a =>
    {
        // do something with the adress
        Console.Writeline(a.Street);
    });

To bad for me, my current project is still on C# 2.0 so I'll keep doing it old school style :-(
Exercise
If you would also like some practice with C# 3.0, I would like challenge you to write something that allows me to do the same thing for IEnumerable, I would like to write something like the following
foreach (Order order in Contract
    .NullSafe(c => c.Parties)
    .NullSafe(p => p.Client)
    .NullSafe(c => c.Orders)
    {
        // do something with order
        Console.Writeline(o.Amount);
    }

Where Client.Orders is of type IEnumerable. The idea is that I want to iterate every Order in Contract.Parties.Client.Orders. If at any stage in the path (including the Orders collection) we encounter a Null reference we will just loop an empty enumerator and do nothing.

No comments:

Post a Comment