2012-12-20 33 views
6

我有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); 

謂詞看看這個: enter image description here

當我在查詢中使用:

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

我得到這個錯誤:類型的 變量 'P' 'BuilderPredicate.MyClass' 從範圍引用 '' ,但它沒有定義

你能告訴我什麼是錯的嗎?

非常感謝,

回答

10

的問題是創建一個新的參數 - 你可以這樣做,但如果你只是把它分配給最終的λ,有一個在提供表達您的參數和原始參數之間沒有連接。嘗試更改表達式的參數名稱,然後檢查finalPredicate。你會看到類似的東西:

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

現在的問題應該是顯而易見的。

馬克Gravell建議在this answer一般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); 
} 

(代碼由Marc,不是我)

+1

我看到馬克的代碼,但沒有奏效不記得爲什麼。但我現在嘗試agrain –

+1

嘗試一下,讓我知道它是否不起作用 - 它對我有用(您只需確保它可以訪問您的代碼,即公開或內部;我會在我的答案中改變它) –

+0

是的,這是工作。不知道我在之前的測試中做了什麼。但說實話,在我的腦海裏並不是很清楚所有這些工作如何:) –