How can I check for nulls in a deep lamda expression?
Say for example I have a class structure that was nested several layers deep, and I wanted to execute the following lambda:
x => x.Two.Three.Four.Foo
I want it to return null if Two, Three, or Four were null, rather than throwing a System.NullReferenceException.
public class Tests
{
    // This test will succeed
    [Fact]
    public void ReturnsValueWhenClass2NotNull()
    {
        var one = new One();
        one.Two = new Two();
        one.Two.Three = new Three();
        one.Two.Three.Four = new Four();
        one.Two.Three.Four.Foo = "blah";
        var result = GetValue(one, x => x.Two.Three.Four.Foo);
        Assert.Equal("blah", result);
    }
    // This test will fail
    [Fact]
    public void ReturnsNullWhenClass2IsNull()
    {
        var one = new One();
        var result = GetValue(one, x => x.Two.Three.Four.Foo);
        Assert.Equal(null, result);
    }
    private TResult GetValue<TModel, TResult>(TModel model, Expression<Func<TModel, TResult>> expression)
    {
        var func = expression.Compile();
        var value = func(model);
        return value;
    }
    public class One
    {
        public Two Two { get; set; }
    }
    public class Two
    {
        public Three Three { get; set; }
    }
    public class Three
    {
        public Four Four { get; set; }
    }
    public class Four
    {
        public string Foo { get; set; }
        public string Bar { get; set; }
    }
}
UPDATE:
One solution would be to catch the NullReferenceException like this:
    private TResult GetValue<TModel, TResult>(TModel model, Expression<Func<TModel, TResult>> expression)
    {
        TResult value;
        try
        {
            var func = expression.Compile();
            value = func(model);
        }
        catch (NullReferenceException)
        {
            value = default(TResult);
        }
        return value;
    }
But I hate to incur the expense of catching an exception that is not, in my mind, exceptional. I expect this to be the case quite often in my domain.
UPDATE 2:
Another solution would be modify the property getters like this:
    public class One
    {
        private Two two;
        public Two Two
        {
            get
            {
                return two ?? new Two();
            }
            set
            {
                two = value;
            }
        }
    }
Which is mostly ok for my domain, but there are times when I really to expect a property to return null. I checked the answer from Josh E as helpful since it comes pretty close to what I need in some cases.
You could do this with a generic helper extension method, something like:
public static class Get {
    public static T IfNotNull<T, U>(this U item, Func<U, T> lambda) where U: class {
        if (item == null) {
            return default(T);
        }
        return lambda(item);
    }
}
var one = new One();
string fooIfNotNull = one.IfNotNull(x => x.Two).IfNotNull(x => x.Three).IfNotNull(x => x.Four).IfNotNull(x => x.Foo);
                        You can't do that in a concise way. You can either make the lambda multiple lines, or use nested ternary operators:
var result = GetValue(one, x => x.Two == null ? null :
                                x.Two.Three == null ? null :
                                x.Two.Three.Four == null ? null :
                                x.Two.Three.Four.Foo;
Ugly, I know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With