产品说,我只需要一个有亿点复杂的查询界面,java注解的实现原理

var rightExp = Expression.Invoke(rightFunc, pExp);

// (a => leftFunc(a))(x) && (a => rightFunc(a))(x)

var bodyExp = Expression.AndAlso(leftExp, rightExp);

// x => (a => leftFunc(a))(x) && (a => rightFunc(a))(x)

var resultEx

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

p = Expression.Lambda<Func<int, bool>>(bodyExp, pExp);

return resultExp;

}

}

只听枯叉一声黑暗渐渐地就分开


但是,上面的方法,其实可以在优化一下。避免对左右表达式的直接调用。

使用一个叫做 Unwrap 的方法,可以将 Lambda Expression 解构成只包含 Body 部分的表达式。

这是一个自定义的扩展方法,你可以通过 ObjectVisitor[1] 来引入这个方法。

限于篇幅,我们此处不能展开谈 Unwrap 的实现。我们只需要关注和前一个示例中注释的不同即可。

[Test]

public void Expression05()

{

var filter = CreateFilter(x => x >= 1, x => x < 5);

var re = Enumerable.Range(0, 10).AsQueryable()

.Where(filter).ToList();

var expectation = Enumerable.Range(1, 4);

re.Should().BeEquivalentTo(expectation);

Expression<Func<int, bool>> CreateFilter(Expression<Func<int, bool>> leftFunc,

Expression<Func<int, bool>> rightFunc)

{

// x

var pExp = Expression.Parameter(typeof(int), “x”);

// leftFunc(x)

var leftExp = leftFunc.Unwrap(pExp);

// rightFunc(x)

var rightExp = rightFunc.Unwrap(pExp);

// leftFunc(x) && rightFunc(x)

var bodyExp = Expression.AndAlso(leftExp, rightExp);

// x => leftFunc(x) && rightFunc(x)

var resultExp = Expression.Lambda<Func<int, bool>>(bodyExp, pExp);

return resultExp;

}

}

天和地分开后盘古怕它们还合并


我们可以再优化以下,把 CreateFilter 方法扩展为支持多个子表达式和可自定义子表达式的连接方式。

于是,我们就可以得到一个 JoinSubFilters 方法。

[Test]

public void Expression06()

{

var filter = JoinSubFilters(Expression.AndAlso, x => x >= 1, x => x < 5);

var re = Enumerable.Range(0, 10).AsQueryable()

.Where(filter).ToList();

var expectation = Enumerable.Range(1, 4);

re.Should().BeEquivalentTo(expectation);

Expression<Func<int, bool>> JoinSubFilters(Func<Expression, Expression, Expression> expJoiner,

params Expression<Func<int, bool>>[] subFilters)

{

// x

var pExp = Expression.Parameter(typeof(int), “x”);

var result = subFilters[0];

foreach (var sub in subFilters[1…])

{

var leftExp = result.Unwrap(pExp);

var rightExp = sub.Unwrap(pExp);

var bodyExp = expJoiner(leftExp, rightExp);

result = Expression.Lambda<Func<int, bool>>(bodyExp, pExp);

}

return result;

}

}

他就头顶着天脚蹬着地不知多久


有了前面的经验,我们知道。其实x => x >= 1这个表达式可以通过一个工厂方法来创建。

所以,我们使用一个 CreateMinValueFilter 来创建这个表达式。

[Test]

public void Expression07()

{

var filter = JoinSubFilters(Expression.AndAlso,

CreateMinValueFilter(1),

x => x < 5);

var re = Enumerable.Range(0, 10).AsQueryable()

.Where(filter).ToList();

var expectation = Enumerable.Range(1, 4);

re.Should().BeEquivalentTo(expectation);

Expression<Func<int, bool>> CreateMinValueFilter(int minValue)

{

return x => x >= minValue;

}

Expression<Func<int, bool>> JoinSubFilters(Func<Expression, Expression, Expression> expJoiner,

params Expression<Func<int, bool>>[] subFilters)

{

// x

var pExp = Expression.Parameter(typeof(int), “x”);

var result = subFilters[0];

foreach (var sub in subFilters[1…])

{

var leftExp = result.Unwrap(pExp);

var rightExp = sub.Unwrap(pExp);

var bodyExp = expJoiner(leftExp, rightExp);

result = Expression.Lambda<Func<int, bool>>(bodyExp, pExp);

}

return result;

}

}

盘古也累得倒下来变成山石河流


当然,可以只使用 Expression 相关的方法来创建x => x >= 1

[Test]

public void Expression08()

{

var filter = JoinSubFilters(Expression.AndAlso,

CreateMinValueFilter(1),

x => x < 5);

var re = Enumerable.Range(0, 10).AsQueryable()

.Where(filter).ToList();

var expectation = Enumerable.Range(1, 4);

re.Should().BeEquivalentTo(expectation);

Expression<Func<int, bool>> CreateMinValueFilter(int minValue)

{

// x

var pExp = Expression.Parameter(typeof(int), “x”);

// minValue

var rightExp = Expression.Constant(minValue);

// x >= minValue

var bodyExp = Expression.GreaterThanOrEqual(pExp, rightExp);

var result = Expression.Lambda<Func<int, bool>>(bodyExp, pExp);

return result;

}

Expression<Func<int, bool>> JoinSubFilters(Func<Expression, Expression, Expression> expJoiner,

params Expression<Func<int, bool>>[] subFilters)

{

// x

var pExp = Expression.Parameter(typeof(int), “x”);

var result = subFilters[0];

foreach (var sub in subFilters[1…])

{

var leftExp = result.Unwrap(pExp);

var rightExp = sub.Unwrap(pExp);

var bodyExp = expJoiner(leftExp, rightExp);

result = Expression.Lambda<Func<int, bool>>(bodyExp, pExp);

}

return result;

}

}

那么看来盘古也吃不了上班的苦


那既然都用了 Expression 来创建子表达式了,那就干脆再做一点点改进,把x => x < 5也做成从工厂方法获取。

[Test]

public void Expression09()

{

var filter = JoinSubFilters(Expression.AndAlso,

CreateValueCompareFilter(Expression.GreaterThanOrEqual, 1),

CreateValueCompareFilter(Expression.LessThan, 5));

var re = Enumerable.Range(0, 10).AsQueryable()

.Where(filter).ToList();

var expectation = Enumerable.Range(1, 4);

re.Should().BeEquivalentTo(expectation);

Expression<Func<int, bool>> CreateValueCompareFilter(Func<Expression, Expression, Expression> comparerFunc,

int rightValue)

{

var pExp = Expression.Parameter(typeof(int), “x”);

var rightExp = Expression.Constant(rightValue);

var bodyExp = comparerFunc(pExp, rightExp);

var result = Expression.Lambda<Func<int, bool>>(bodyExp, pExp);

return result;

}

Expression<Func<int, bool>> JoinSubFilters(Func<Expression, Expression, Expression> expJoiner,

params Expression<Func<int, bool>>[] subFilters)

{

// x

var pExp = Expression.Parameter(typeof(int), “x”);

var result = subFilters[0];

foreach (var sub in subFilters[1…])

{

var leftExp = result.Unwrap(pExp);

var rightExp = sub.Unwrap(pExp);

var bodyExp = expJoiner(leftExp, rightExp);

result = Expression.Lambda<Func<int, bool>>(bodyExp, pExp);

}

return result;

}

}

所以如果可以不做这需求就别搞


最后,我们在把子表达式的创建通过一点点小技巧。通过外部参数来决定。就基本完成了一个多 And 的值比较查询条件的动态构建。

[Test]

public void Expression10()

{

var config = new Dictionary<string, int>

{

{ “>=”, 1 },

{ “<”, 5 }

};

var subFilters = config.Select(x => CreateValueCompareFilter(MapConfig(x.Key), x.Value)).ToArray();

var filter = JoinSubFilters(Expression.AndAlso, subFilters);

var re = Enumerable.Range(0, 10).AsQueryable()

.Where(filter).ToList();

var expectation = Enumerable.Range(1, 4);

re.Should().BeEquivalentTo(expectation);

Func<Expression, Expression, Expression> MapConfig(string op)

{

return op switch

{

“>=” => Expression.GreaterThanOrEqual,

“<” => Expression.LessThan,

_ => throw new ArgumentOutOfRangeException(nameof(op))

};

}

Expression<Func<int, bool>> CreateValueCompareFilter(Func<Expression, Expression, Expression> comparerFunc,

int rightValue)

{

var pExp = Expression.Parameter(typeof(int), “x”);

var rightExp = Expression.Constant(rightValue);

var bodyExp = comparerFunc(pExp, rightExp);

var result = Expression.Lambda<Func<int, bool>>(bodyExp, pExp);

return result;

}

Expression<Func<int, bool>> JoinSubFilters(Func<Expression, Expression, Expression> expJoiner,

params Expression<Func<int, bool>>[] subFilters)

{

// x

var pExp = Expression.Parameter(typeof(int), “x”);

var result = subFilters[0];

foreach (var sub in subFilters[1…])

{

var leftExp = result.Unwrap(pExp);

var rightExp = sub.Unwrap(pExp);

上一篇:[C# Expression] 之动态创建表达式


下一篇:遇到一个大坑