A long precarious way…

TL;DR; = This post is about improving the way you write deep null checks in C#, i.e. a chain of If-not-null checks along the object hierarchy.

I am sure there have been times in your developer life when you saw something like this, 


class Person
{
public Address Address { get; set; }
}

public class Address
{
public State State { get; set; }
}

public class State
{
public int PinCode { get; set; }
}
...
...
var p = new Person();
...
...

if (p.Address != null && p.Address.State != null)
{
var pin = p.Address.State.PinCode;
}


Ugh.., yes you have… The point is you have to go through a lot of checks in between to reach the PinCode field. In this example there are just 2 checks for Address and State, but there could be more complicated scenarios. While talking about this, I do understand by the Law of Demeter we should not be having such deep checks in the first place. But for this blog post sake, consider this as some hairy legacy code. Moving on, there is a way you could do the same thing but in a much more readable way. What I want to do is in case of a null instance anywhere in the chain of objects, the final value should be a default decided by me, without any null reference error. Here is my attempt,




public static class Extension
{
public static TResult With<TSource,TResult>(this TSource source, Func<TSource,TResult> evaluator, TResult failureValue)
where TSource : class
where TResult : class
{
if (evaluator == null)
throw new InvalidOperationException("Boom!!!");
var res = source != null ? evaluator(source) : failureValue;
return res ?? failureValue;
}
}

public class Person
{
public Address Address { get; set; }
public static Person NullInstance
{
get
{
return new Person() { Address = Address.NullInstance };
}
}
}

public class Address
{
public State State { get; set; }
public static Address NullInstance
{
get { return new Address() { State = State.NullInstance }; }
}

}

public class State
{
public int PinCode { get; set; }
public static State NullInstance
{
get
{
return new State() { PinCode = -1 };
}
}
}

...
...

var pin = this.With(x => p, Person.NullInstance)
.With(x => x.Address, Address.NullInstance)
.With(x => x.State, State.NullInstance).PinCode;


Definitely more readable huh.

0 Comments:

Post a Comment