8

述語が 3 つあります。間に入れたいと思いAndAlsoます。ボード上にいくつかのサンプルが見つかりましたが、問題を解決できません。

これらの述語は次のとおりです。Expression<Func<T, bool>>

私はこのコードを持っています:

Expression<Func<T, bool>> predicate1 = ......;
Expression<Func<T, bool>> predicate2 = ......;
Expression<Func<T, bool>> predicate3 = ......;

"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]);
}

私はこのように使用します:

var finalPredicate = predicate1
    .AndAlso<MyClass>(predicate2)
    .AndAlso<MyClass>(predicate3);

述語はこれを見てください: ここに画像の説明を入力

クエリで使用する場合:

var res =  myListAsQueryable().Where(finalPredicate).ToList<MyClass>();

次のエラーが表示されます: タイプ 'BuilderPredicate.MyClass' の変数 'p' がスコープ '' から参照されていますが、定義されていません

何が悪いのか教えていただけますか?

どうもありがとう、

4

1 に答える 1

14

問題は、新しいパラメーターを作成することです。それはできますが、それを最終的なラムダに割り当てるだけでは、パラメーターと提供された式の元のパラメーターとの間に接続がありません。式のパラメータ名を変更してみて、finalPredicate. 次のようなものが表示されます。

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

問題は今明らかなはずです。

Marc Gravell は、この回答で generalを提案して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);
}

(私ではなく、マークによるコード)

于 2012-12-20T08:42:09.330 に答える