Possible pitfalls of using this (extension method based) shorthand

We independently came up with the exact same extension method name and implementation: Null-propagating extension method. So we don't think it's confusing or an abuse of extension methods.

I would write your "multiple levels" example with chaining as follows:

propertyValue1 = myObject.IfNotNull(o => o.ObjectProp).IfNotNull(p => p.StringProperty);

There's a now-closed bug on Microsoft Connect that proposed "?." as a new C# operator that would perform this null propagation. Mads Torgersen (from the C# language team) briefly explained why they won't implement it.


Here's another solution, for chained members, including extension methods:

public static U PropagateNulls<T,U> ( this T obj
                                     ,Expression<Func<T,U>> expr) 
{  if (obj==null) return default(U);

   //uses a stack to reverse Member1(Member2(obj)) to obj.Member1.Member2 
   var members = new Stack<MemberInfo>();

   bool       searchingForMembers = true;
   Expression currentExpression   = expr.Body;

   while (searchingForMembers) switch (currentExpression.NodeType)
    { case ExpressionType.Parameter: searchingForMembers = false; break;

           case ExpressionType.MemberAccess:    
           { var ma= (MemberExpression) currentExpression;
             members.Push(ma.Member);
             currentExpression = ma.Expression;         
           } break;     

          case ExpressionType.Call:
          { var mc = (MethodCallExpression) currentExpression;
            members.Push(mc.Method);

           //only supports 1-arg static methods and 0-arg instance methods
           if (   (mc.Method.IsStatic && mc.Arguments.Count == 1) 
               || (mc.Arguments.Count == 0))
            { currentExpression = mc.Method.IsStatic ? mc.Arguments[0]
                                                     : mc.Object; 
              break;
            }

           throw new NotSupportedException(mc.Method+" is not supported");
         } 

        default: throw new NotSupportedException
                        (currentExpression.GetType()+" not supported");
  }

   object currValue = obj;
   while(members.Count > 0)
    { var m = members.Pop();

      switch(m.MemberType)
       { case MemberTypes.Field:
           currValue = ((FieldInfo) m).GetValue(currValue); 
           break;

         case MemberTypes.Method:
           var method = (MethodBase) m;
           currValue = method.IsStatic
                              ? method.Invoke(null,new[]{currValue})
                              : method.Invoke(currValue,null); 
           break;

         case MemberTypes.Property:
           var method = ((PropertyInfo) m).GetGetMethod(true);
                currValue = method.Invoke(currValue,null);
           break;

       }     

      if (currValue==null) return default(U);   
    }

   return (U) currValue;    
}

Then you can do this where any can be null, or none:

foo.PropagateNulls(x => x.ExtensionMethod().Property.Field.Method());

If you find yourself having to check very often if a reference to an object is null, may be you should be using the Null Object Pattern. In this pattern, instead of using null to deal with the case where you don't have an object, you implement a new class with the same interface but with methods and properties that return adequate default values.


How is

propertyValue1 = myObject.IfNotNull(o => o.ObjectProp.IfNotNull( p => p.StringProperty ) );

easier to read and write than

if(myObject != null && myObject.ObjectProp != null)
    propertyValue1 = myObject.ObjectProp.StringProperty;

Jafar Husain posted a sample of using Expression Trees to check for null in a chain, Runtime macros in C# 3.

This obviously has performance implications though. Now if only we had a way to do this at compile time.


I just have to say that I love this hack!

I hadn't realized that extension methods don't imply a null check, but it totally makes sense. As James pointed out, The extension method call itself is not any more expensive than a normal method, however if you are doing a ton of this, then it does make sense to follow the Null Object Pattern, that ljorquera suggested. Or to use a null object and ?? together.

class Class1
{
    public static readonly Class1 Empty = new Class1();
.
.
x = (obj1 ?? Class1.Empty).X;