动态|如何完成复杂查询的动态构建?( 三 )


引入表达式的解构 , 使其更加简单
但是 , 上面的方法 , 其实可以再优化一下 。 避免对左右表达式的直接调用 。
使用一个叫做 Unwrap 的方法 , 可以将 Lambda Expression 解构成只包含 Body 部分的表达式 。
这是一个自定义的扩展方法 , 你可以通过 ObjectVisitor 来引入这个方法 。
限于篇幅 , 我们此处不能展开谈 Unwrap 的实现 。 我们只需要关注和前一个示例中注释的不同即可 。

  • ObjectVisitor : https://github.com/newbe36524/Newbe.ObjectVisitor
[ Test] publicvoidExpression05( ) {varfilter = CreateFilter(x => x >= 1, x => x < 5); varre = Enumerable.Range( 0, 10).AsQueryable .Where(filter).ToList;varexpectation = Enumerable.Range( 1, 4); re.Should.BeEquivalentTo(expectation);Expression<Func< int, bool>> CreateFilter(Expression<Func< int, bool>> leftFunc, Expression<Func< int, bool>> rightFunc) {// xvarpExp = Expression.Parameter( typeof( int), "x"); // leftFunc(x)varleftExp = leftFunc.Unwrap(pExp); // rightFunc(x)varrightExp = rightFunc.Unwrap(pExp); // leftFunc(x) && rightFunc(x)varbodyExp = Expression.AndAlso(leftExp, rightExp); // x => leftFunc(x) && rightFunc(x)varresultExp = Expression.Lambda<Func< int, bool>>(bodyExp, pExp); returnresultExp; }}
可以拼接更多的表达式
我们可以再优化以下 , 把 CreateFilter 方法扩展为支持多个子表达式和可自定义子表达式的连接方式 。
于是 , 我们就可以得到一个 JoinSubFilters 方法 。
[ Test] publicvoidExpression06( ) {varfilter = JoinSubFilters(Expression.AndAlso, x => x >= 1, x => x < 5); varre = Enumerable.Range( 0, 10).AsQueryable .Where(filter).ToList;varexpectation = Enumerable.Range( 1, 4); re.Should.BeEquivalentTo(expectation);Expression<Func< int, bool>> JoinSubFilters(Func<Expression, Expression, Expression> expJoiner, paramsExpression<Func< int, bool>>[] subFilters) {// xvarpExp = Expression.Parameter( typeof( int), "x"); varresult = subFilters[ 0]; foreach( varsub insubFilters[ 1..]) {varleftExp = result.Unwrap(pExp); varrightExp = sub.Unwrap(pExp); varbodyExp = expJoiner(leftExp, rightExp);
result = Expression.Lambda<Func< int, bool>>(bodyExp, pExp); }
returnresult; }}
使用工厂方法来代替固定的子表达式
有了前面的经验 , 我们知道 。 其实x => x >= 1这个表达式可以通过一个工厂方法来建 。

推荐阅读