如何正确合并具有不同参数的 lambda 表达式

How to properly merge lambda-expressions with different parameters

我有两个表达方式:

Expression<Func<long, bool>> condition = x => x < max; // Exp # 1

if (count > 0)
{
    Expression<Func<int, bool>> limit = x => x > -1; // Exp # 2
    condition = Expression.Lambda<Func<long, bool>>(
                Expression.AndAlso(condition, limit), condition.Parameters);
}

var comparator = condition.Compile();

while (comparator(k++, n--))
{
    // Something
}

下面的代码可以编译,但是它只需要一个 "long" 类型的参数到组合的 lambda 中,我怎样才能将两个不同的参数传递到组合的 lambda 中?

我现在手头没有 Visual Studio,但凭直觉你试过这个看看是否有效:

if (count > 0)
{
    Expression<Func<int, bool>> limit = x => x > -1; // Exp # 2
    condition = Expression.Lambda<Func<long, int, bool>>(
                Expression.AndAlso(condition, limit), condition.Parameters);
}

这将为新组合的 Lambda 提供一个接受两个参数和 returns 布尔值的签名。您可能还需要在 condition.Parameters 之后执行一些操作以将 limit.parameters 也包括在内。

首先,您需要使 condition 具有两个输入的表达式。当不与第二个表达式组合时,将第二个(未使用的)参数添加到 lambda 定义中。组合两个表达式时,在要组合的表达式周围添加 Invoke。否则,您将收到一个运行时错误,告诉您 Func<int,bool>Func<long,bool> 不能与 && 运算符组合。

以下是实现方法:

Expression<Func<long,int,bool>> condition;

Expression<Func<long,bool>> exp1 = x => x < max;

if (count > 0)
{
    Expression<Func<int,bool>> exp2 = x => x > -1;
    condition = Expression.Lambda<Func<long,int,bool>>(
            Expression.AndAlso(
                Expression.Invoke(exp1, exp1.Parameters)
            ,   Expression.Invoke(exp2, exp2.Parameters)
            )
        ,   exp1.Parameters.Concat(exp2.Parameters)
        );
} else {
    condition = Expression.Lambda<Func<long,int,bool>>(
        Expression.Invoke(exp1, exp1.Parameters)
        ,   exp1.Parameters.Concat(new[]{Expression.Parameter(typeof(int))})
        );
}
var comparator = condition.Compile();

Demo.

Expression<Func<long, bool>> condition = x => x < max; // Exp # 1
Expression<Func<long, int, bool>> combined = null;

if (count > 0)
{
    Expression<Func<int, bool>> limit = x => x > -1; // Exp # 2
    combined = Expression.Lambda<Func<long, int, bool>>(
        Expression.And(condition.Body, limit.Body), 
        new ParameterExpression[] 
        {
            condition.Parameters[0], 
            limit.Parameters[0] 
        }
    );
} else {
    // Count <= 0, `int` parameter will be provided, but `body` ignores it
    combined = Expression.Lambda<Func<long, int, bool>>(
        condition.Body, 
        new ParameterExpression[] 
        {
            condition.Parameters[0], 
            limit.Parameters[0] 
        }
    );
}

// compile `combined` expression
var comparator = combined.Compile();

while (comparator(k++, n--))
{
    // Something
}