c# - 将多个不同类型的 lambda 表达式组合成一个表达式
问题描述
我想组合一些分离的 lambda 表达式并构建它们的最终表达式。
示例类:
class Address {
public string city { get; set; }
public string country { get; set; }
}
class ClassA {
public int Id { get; set; }
public Address address { get; set; }
}
class ClassB {
public int Id { get; set; }
public ClassA objectA { get; set; }
}
每个类都有一个 lambda 表达式:
Expression<Func<ClassA,bool>> classARule = a =>
a.Id > 1 && a.address.city == "city1" || a.address.country == "us"
Expression<Func<ClassB,bool>> classBRule = b => b.Id == 100
因为ClassB
有一个属性,ClassA
可以创建同时具有这两个条件的表达式。例子 :
// I want to create this expected object at runtime using classARule and classBRule
Expression<Func<ClassB,bool>> expected = b =>
(b.Id == 100) &&
(b.objectA.Id > 1 && b.objectA.address.city == "city1" || b.objectA.address.country == "us")
如果我想在运行时生成预期的表达式,我应该以某种方式将a
参数转换classARule
为b.objectA
问题是我知道如何组合两个表达式,但我不知道如何a
用其他对象替换参数。在这种情况下b.objectA
更新 - 为了避免更多的混乱
目标是在运行时使用和实现Expression<Func<ClassB,bool>> expected
表达classARule
classBRule
解决方案
幸运的是,我解决了这个问题。如果遇到这样的问题,这里的最终结果是给其他人的。
public static Expression<Func<B, bool>> Combine<B, A>(this Expression<Func<B, bool>> expr1, Expression<Func<A, bool>> expr2, Expression<Func<B, A>> property)
{
// this is (q) parameter of my property
var replaceParameter = property.Parameters[0];
// replacing all (b) parameter with the (q)
// these two lines converts `b => b.Id == 100` to `q => q.Id == 100`
// using ReplaceExpVisitor class
var leftVisitor = new ReplaceExpVisitor(replaceParameter);
var left = leftVisitor.Visit(expr1.Body);
// the property body is 'q.objectA'
var replaceBody = property.Body;
// now i'm replacing every (a) parameter of my second expression to 'q.objectA'
// these two lines convert this statement:
// a.Id > 1 && a.address.city == "city1" || a.address.country == "us"
// to this :
// q.objectA.Id > 1 && q.objectA.address.city == "city1" || q.objectA.address.country == "us"
var rightVisitor = new ReplaceExpVisitor(replaceBody);
var right = rightVisitor.Visit(expr2.Body);
// creating new expression and pass (q) reference to it (replaceParameter).
return Expression.Lambda<Func<B, bool>>(Expression.AndAlso(left, right), replaceParameter);
}
// this is a simple class to replace all parameters with new expression
private class ReplaceExpVisitor : ExpressionVisitor
{
private readonly Expression _newval;
public ReplaceExpVisitor(Expression newval) => _newval = newval;
protected override Expression VisitParameter(ParameterExpression node)
{
return _newval;
}
}
用法 :
var result = classBRule.Combine(classARule, q => q.objectA);
// or
Expression<Func<ClassB,bool>> result =
Combine<ClassB, ClassA>(classBRule, classARule, q => q.objectA);
/*
result is equal to the expected expression in the first example now
result output :
q =>
((q.Id == 100) &&
(((q.objectA.Id > 1) && (q.objectA.address.city == "city1")) ||
(q.objectA.address.country == "us")))
*/
推荐阅读
- if-statement - 具有多个返回值的方法的“if”初始化语句
- python - Python 直接访问 Login 而不使用 With Function as Key :
- java - 从使用 GNU Make 编译 Java 到 gradle
- c# - 如何在不使用 .Add() 方法的情况下将项目添加到我的通用自定义列表?
- r - gmax中的错误(
) : 找不到对象“my_variable” - php - var_dump 数组返回我的字符串,双倍?
- java - 背景图像未填充布局并在上方和下方占用额外空间
- html - 我希望我的 jQueryUI 范围滑块根据输入值动态移动
- sql - 获取不包括周末的最后 5 天记录?
- .htaccess - .htaccess 允许从本地主机读取 css 和普通的东西