并且还要在几个Expression <Func <T,bool >>之间:从范围引用

Kri*_*s-I 6 .net c# lambda expression

我有3个谓词,我想要AndAlso介于两者之间.我在板上发现了几个样本,但无法解决我的问题.

这些谓词是: Expression<Func<T, bool>>

我有这个代码:

Expression<Func<T, bool>> predicate1 = ......;
Expression<Func<T, bool>> predicate2 = ......;
Expression<Func<T, bool>> predicate3 = ......;
Run Code Online (Sandbox Code Playgroud)

我创建了一个扩展方法来创建一个"AndAlso":

public static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr, 
    Expression<Func<T, bool>> exprAdd)
{
    var param = Expression.Parameter(typeof(T), "p");
    var predicateBody = Expression.AndAlso(expr.Body, exprAdd.Body);
    return Expression.Lambda<Func<T, bool>>(predicateBody, param);

    //Tried this too
    //var body = Expression.AndAlso(expr.Body, exprAdd.Body);
    //return Expression.Lambda<Func<T, bool>>(body, expr.Parameters[0]);
}
Run Code Online (Sandbox Code Playgroud)

我用这样的:

var finalPredicate = predicate1
    .AndAlso<MyClass>(predicate2)
    .AndAlso<MyClass>(predicate3);
Run Code Online (Sandbox Code Playgroud)

谓词看起来像这样: 在此输入图像描述

当我在查询中使用时:

var res =  myListAsQueryable().Where(finalPredicate).ToList<MyClass>();
Run Code Online (Sandbox Code Playgroud)

我得到这个错误: 从范围''引用的'BuilderPredicate.MyClass'类型的变量'p',但它没有定义

你能告诉我什么是错的吗?

非常感谢,

Hon*_*tan 11

问题是创建一个新参数 - 您可以这样做,但如果您只是将其分配给最终的lambda,则您的参数与提供的表达式中的原始参数之间没有任何关联.尝试更改表达式的param名称,然后检查finalPredicate.你会看到类似的东西:

{p => (((x.Age == 42) AndAlso (y.Salary == 50)) AndAlso z.FirstName.StartsWith("foo"))}
Run Code Online (Sandbox Code Playgroud)

问题现在应该是显而易见的.

Marc Gravell在这个答案中建议一般Expression.AndAlso,这正是你需要的:

public static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr1,
    Expression<Func<T, bool>> expr2)
{
    // need to detect whether they use the same
    // parameter instance; if not, they need fixing
    ParameterExpression param = expr1.Parameters[0];
    if (ReferenceEquals(param, expr2.Parameters[0]))
    {
        // simple version
        return Expression.Lambda<Func<T, bool>>(
            Expression.AndAlso(expr1.Body, expr2.Body), param);
    }
    // otherwise, keep expr1 "as is" and invoke expr2
    return Expression.Lambda<Func<T, bool>>(
        Expression.AndAlso(
            expr1.Body,
            Expression.Invoke(expr2, param)), param);
}
Run Code Online (Sandbox Code Playgroud)

(Marc代码,不是我)