You can use Expression solution. Below is a basic and functional solution for calling a circuit / network. It will work for very deep chains of calls. This is not perfect. For example, it does not work if there is a method call in the chain ( obj.Prop1.MethodCall (). Prop2 ).
Expression-based solutions are usually slower , due to the need to compile a lambda expression for delegation , which should be taken into account .
Performance Statistics :
Tests with a collection of 200k objects with a nested call level of 2 (obj.Prop1.Prop2), where all objects fail for the condition.
LINQ Where with C # 6 ?. operator: 2 - 4 ms
Exception based (try / catch): 14,000 - 15,000 ms
Based on expression: 4 - 10 ms
NOTE An expression-based solution will add overhead of several ms for each call, this number will not depend on the size of the collection, as the expression will be compiled for each call, which is an expensive operation. You can think of a cache mechanism if you are interested.
Source for the solution based on the expression ::
public static IEnumerable<T> IgnoreIfNull<T, TProp>(this IEnumerable<T> sequence, Expression<Func<T, TProp>> expression) { var predicate = BuildNotNullPredicate(expression); return sequence.Where(predicate); } private static Func<T, bool> BuildNotNullPredicate<T, TProp>(Expression<Func<T, TProp>> expression) { var root = expression.Body; if (root.NodeType == ExpressionType.Parameter) { return t => t != null; } var pAccessMembers = new List<Expression>(); while (root.NodeType == ExpressionType.MemberAccess) { var mExpression = root as MemberExpression; pAccessMembers.Add(mExpression); root = mExpression.Expression; } pAccessMembers.Reverse(); var body = pAccessMembers .Aggregate( (Expression)Expression.Constant(true), (f, s) => { if (s.Type.IsValueType) { return f; } return Expression.AndAlso( left: f, right: Expression.NotEqual(s, Expression.Constant(null)) ); }); var lambda = Expression.Lambda<Func<T, bool>>(body, expression.Parameters[0]); var func = lambda.Compile(); return func; }
Here's how to do it:
var sequence = .... var filtered = sequence.IgnoreIfNull(x => x.Prop1.Prop2.Prop3 ... etc);