动态Linq不容忍null属性

时间:2017-07-20 20:57:55

标签: c# linq dynamic-linq

我有这样的代码,其中数据库DDL在运行时被转换为Dynamic Linq以定义过滤器。除了一些过滤器引用可以为null的子属性之外,代码有效。应用规则时,null会导致整个语句爆炸。

举个例子:

// 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

由于我在运行时收到对象和过滤器(此处定义为filterExpression),因此如果找到Null属性,我需要一些方法来“转义”Linq序列。不幸的是,添加Null检查似乎没有帮助,因为无论nullExpression的结果如何,filterExpression都会爆炸。我不确定我是否写了动态Linq错误或者是否有其他方法可以解决这个问题。有什么想法吗?

例外

System.NullReferenceException: Object reference not set to an instance of an object.
   at lambda_method(Closure , ParentObject )

1 个答案:

答案 0 :(得分:2)

查看以下用作概念证明的单元测试。

[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; }
    }
}

您应该能够查看注释并将其用作构建动态表达式的示例