[ Test] publicvoidExpression03( ) {varfilter = CreateFilter(x = x = 1, x = x 5); varre = Enumerable.Range( 0, 10).AsQueryable .Where(filter).ToList;varexpectation = Enumerable.Range( 1, 4); re.Should....
[ Test] publicvoidExpression03( ) {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(Func< int, bool> leftFunc, Func< int, bool> rightFunc) {returnx => leftFunc.Invoke(x) && rightFunc.Invoke(x); }}
也可以手动构建表达式
实际上 , 左右两个不仅仅是两个Func , 其实也可以直接是两个表达式 。
不过稍微有点不同的是 , 表达式的合并需要用 Expression 类型中的相关方法创建 。
我们可以发现 , 调用的地方这次其实没有任何改变 , 因为 Lambda 既可以隐式转换为 Func 也可以隐式转换为 Expression 。
每个方法的意思可以从注释中看出 。
[ Test] publicvoidExpression04( ) {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"); // (a => leftFunc(a))(x)varleftExp = Expression.Invoke(leftFunc, pExp); // (a => rightFunc(a))(x)varrightExp = Expression.Invoke(rightFunc, pExp); // (a => leftFunc(a))(x) && (a => rightFunc(a))(x)varbodyExp = Expression.AndAlso(leftExp, rightExp); // x => (a => leftFunc(a))(x) && (a => rightFunc(a))(x)varresultExp = Expression.Lambda<Func< int, bool>>(bodyExp, pExp); returnresultExp; }}
引入表达式的解构 , 使其更加简单
但是 , 上面的方法 , 其实可以再优化一下 。 避免对左右表达式的直接调用 。
使用一个叫做 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 方法 。