You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何合并多个Expression<Func<T,string>>为同一Lambda参数的Lambda表达式

解决多Expression合并时的Lambda参数统一问题

直接上可行的实现方案,核心是用表达式访问器把所有原有Expression里的参数替换成同一个实例,再拼接成OR逻辑:

步骤1:写一个参数替换器

这个类继承ExpressionVisitor,用来把原有表达式里的参数替换成我们指定的统一参数:

class ParameterReplacer : ExpressionVisitor
{
    private readonly ParameterExpression _newParam;

    public ParameterReplacer(ParameterExpression newParam)
    {
        _newParam = newParam;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        // 把所有遇到的原有参数替换成新的统一参数
        return _newParam;
    }
}

步骤2:拼接表达式的核心逻辑

public static Expression<Func<T, bool>> BuildOrContainsLambda<T>(
    Expression<Func<T, string>>[] propertyExpressions, 
    string searchStr)
{
    // 1. 创建统一的Lambda参数
    var param = Expression.Parameter(typeof(T), "m");
    
    // 2. 准备Contains方法和常量表达式
    var strConstant = Expression.Constant(searchStr, typeof(string));
    var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
    
    // 3. 遍历所有输入表达式,逐个处理并合并成OR逻辑
    Expression combinedCondition = null;
    foreach (var expr in propertyExpressions)
    {
        // 替换当前表达式的参数为统一参数
        var replacedPropertyExpr = new ParameterReplacer(param).Visit(expr.Body);
        // 生成「属性.Contains(searchStr)」的表达式
        var containsExpr = Expression.Call(replacedPropertyExpr, containsMethod, strConstant);
        
        // 合并到总条件里,第一个条件直接赋值,后续用OrElse拼接
        combinedCondition = combinedCondition == null 
            ? containsExpr 
            : Expression.OrElse(combinedCondition, containsExpr);
    }
    
    // 4. 生成最终的Lambda表达式
    return Expression.Lambda<Func<T, bool>>(combinedCondition, param);
}

示例用法

假设你的实体类是Person:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

// 输入的表达式数组
var propertyExprs = new Expression<Func<Person, string>>[]
{
    p => p.FirstName,
    p => p.LastName
};
string searchStr = "Doe";

// 生成目标Lambda
var finalLambda = BuildOrContainsLambda<Person>(propertyExprs, searchStr);
// 最终Lambda等价于:p => p.FirstName.Contains("Doe") || p.LastName.Contains("Doe")

为什么要这么做?

每个原始的Expression<Func<T, string>>都有自己独立的ParameterExpression实例——哪怕参数名称都是m或者p,Expression树都会把它们当成不同的参数。如果直接用这些不同的参数拼接OrElse表达式,最后调用Expression.Lambda时会因为参数不统一报错,所以必须用替换器把所有参数换成同一个实例。

内容的提问来源于stack exchange,提问作者buga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 06:12:28