Dynamic Linq not tolerating null property

c# dynamic-linq linq

Question

I have this code in which a database DDL is turned into Dynamic Linq at runtime to define a filter.The code works, except that some filters refer to a child property that can be null. When the rule is applied the null causes the entire statement to explode.

As an example:

// filter is to see if ParentObject.ChildObject.ChildProperty > 1
var param = Expression.Parameter(typeof(ParentObject));
var nullExpression = Expression.NotEqual(Expression.PropertyOrField(param, "ChildObject"), Expression.Constant(null));
var propertyExpression = Expression.Constant(ChildProperty);
var filterExpression = Expression.MakeBinary(ExpressionType.GreaterThan, propertyExpression, typeof(ChildObject));
var finalExpression = Expression.Add({nullExpression, propertyExpression});

var compiledExpression = Expression.Lambda<Func<T, bool>>(finalExpression, param).Compile() //Compilation will succeed
var isTrue = compiledExpression(ParentObject); //If ChildObject is null, this will explode

Since I receive the object and the filter (defined here as filterExpression) at runtime I need some way to 'escape' the Linq sequence if the Null property is found. Unfortunately adding the Null check doesn't seem to have helped as the filterExpression will explode irregardless of the outcome of the nullExpression. I'm not certain if I've written the dynamic Linq wrong or if there is another way of going about this. Any ideas?

The Exception:

System.NullReferenceException: Object reference not set to an instance of an object.
   at lambda_method(Closure , ParentObject )
1
1
7/20/2017 10:35:11 PM

Accepted Answer

Review the following Unit test used as a proof of concept.

[TestClass]
public class UnitTest5 {
    [TestMethod]
    public void _MyTestMethod1() {
        var target = new ParentObject {
            ChildObject = new ChildObject {
                ChildProperty = 5
            }
        };
        Assert.IsTrue(TestMethod1(target));
    }

    [TestMethod]
    public void _MyTestMethod2() {
        var target = new ParentObject {

        };
        Assert.IsFalse(TestMethod1(target));
    }

    public bool TestMethod1<T>(T ParentObject) {

        // filter is to see if ParentObject.ChildObject.ChildProperty > 1            
        // p => p.ChildObject != null && p.ChildObject.ChildProperty > 1

        // p => ...
        var param = Expression.Parameter(typeof(T));
        // p => p.ChildObject
        var childObjectExpression = Expression.PropertyOrField(param, "ChildObject");
        // p => p.ChildObject != null
        var nullExpression = Expression.NotEqual(childObjectExpression, Expression.Constant(null));
        // p => p.ChildObject.ChildProperty
        var childPropertyExpression = Expression.Property(childObjectExpression, "ChildProperty");
        // p => p.ChildObject.ChildProperty > 1
        var greaterThanExpression = Expression.MakeBinary(ExpressionType.GreaterThan, childPropertyExpression, Expression.Constant(1));
        // p => p.ChildObject != null && p.ChildObject.ChildProperty > 1
        var finalExpression = Expression.AndAlso(nullExpression, greaterThanExpression);

        var compiledExpression = Expression.Lambda<Func<T, bool>>(finalExpression, param).Compile();//Compilation will succeed
        var isTrue = compiledExpression(ParentObject);
        return isTrue;
    }

    public class ParentObject {
        public ChildObject ChildObject { get; set; }
    }

    public class ChildObject {
        public int ChildProperty { get; set; }
    }
}

You should be able to look at the comments and use this as an example as the dynamic expression is built

2
7/21/2017 1:01:02 AM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow