よりスリムにnull チェックを行う

.net 4.0 - Cleaner way to do a null check in C#? - Stack Overflow
Sansan公式メディア「mimi」
でCheckNullが気持ち悪いので消してみた。+αデフォルト値を返せるようにしてみた

using System;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;

namespace IsNullTest
{
    public class IsNullVisitor : ExpressionVisitor
    {
        public bool IsNull { get { return null == CurrentObject; } }
        public object CurrentObject { get; set; }

        protected override Expression VisitMember(MemberExpression node)
        {
            base.VisitMember(node);

            if (!IsNull)
            {
                var member = (PropertyInfo)node.Member;
                CurrentObject = member.GetValue(CurrentObject, null);
            }

            return node;
        }
    }

    public static class Helper
    {
        public static bool IsNull<T>(this T root, Expression<Func<T, object>> getter)
        {
            var visitor = new IsNullVisitor() { CurrentObject = root };
            visitor.Visit(getter);
            return visitor.IsNull;
        }
        public static U IfNull<T, U>(this T root, U defaultValue, Expression<Func<T, U>> getter)
        {
            var visitor = new IsNullVisitor() { CurrentObject = root };
            visitor.Visit(getter);
            if (visitor.IsNull)
            {
                return defaultValue;
            }
            else
            {
                return (U)visitor.CurrentObject;
            }
        }
    }

    class Contact
    {
        public Address address { get; set; }
    }

    class Address
    {
        public string city { get; set; }
        public int integer { get; set; }
        public float real { get; set; }
    }

    class Person 
    {
        public Contact contact { get; set; }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Person nullPerson = null;
            Debug.Assert(true == nullPerson.IsNull(p => p.contact.address.city));
            Debug.Assert(true == new Person().IsNull(p => p.contact.address.city));
            Debug.Assert(true == new Person { contact = new Contact() }.IsNull(p => p.contact.address.city));
            Debug.Assert(true == new Person { contact = new Contact { address = new Address() } }.IsNull(p => p.contact.address.city));
            Debug.Assert(true == nullPerson.IsNull(p => p));
            Debug.Assert(true == nullPerson.IsNull(p => p.contact));

            Debug.Assert(false == new Person { contact = new Contact { address = new Address { city = "LONDON" } } }.IsNull(p => p.contact.address.city));
            Debug.Assert("NY" == nullPerson.IfNull("NY", p => p.contact.address.city));

            Debug.Assert(true == nullPerson.IsNull(p => p.contact.address.integer));
            Debug.Assert(100 == nullPerson.IfNull(100, p => p.contact.address.integer));
            Debug.Assert(false == new Person { contact = new Contact { address = new Address { integer = 100 } } }.IsNull(p => p.contact.address.integer));
            Debug.Assert(100 == new Person { contact = new Contact { address = new Address { integer = 100 } } }.IfNull(0, p => p.contact.address.integer));
            
            Debug.Assert(0.1f == nullPerson.IfNull(0.1f, p => p.contact.address.real));
            Debug.Assert(0.1f == new Person { contact = new Contact { address = new Address { real = 0.1f } } }.IfNull(0, p => p.contact.address.real));
        }
    }
}