2009-01-04 112 views
8

我試圖寫一個靜態函數或兩個表達式,但收到以下錯誤:Expression.Or,參數「項目」不在範圍內

The parameter 'item' is not in scope.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The parameter 'item' is not in scope.

方法:

public static Expression<Func<T, bool>> OrExpressions(Expression<Func<T, bool>> left, Expression<Func<T, bool>> right) 
{ 
    // Define the parameter to use 
    var param = Expression.Parameter(typeof(T), "item"); 

    var filterExpression = Expression.Lambda<Func<T, bool>> 
     (Expression.Or(
      left.Body, 
      right.Body 
     ), param); 
    // Build the expression and return it 
    return (filterExpression); 
} 

編輯:增加更多的信息

正在或運算表達式是由下面的方法,它執行就好了過來。如果還有更好的辦法或者結果我全都耳熟能詳。另外,我不知道有多少人正在提前。

public static Expression<Func<T, bool>> FilterExpression(string filterBy, object Value, FilterBinaryExpression binaryExpression) 
{ 
    // Define the parameter to use 
    var param = Expression.Parameter(typeof(T), "item"); 

    // Filter expression on the value 
    switch (binaryExpression) 
    { 
     case FilterBinaryExpression.Equal: 
      { 
       // Build an expression for "Is the parameter equal to the value" by employing reflection 
       var filterExpression = Expression.Lambda<Func<T, bool>> 
        (Expression.Equal(
         Expression.Convert(Expression.Property(param, filterBy), typeof(TVal)), 
         Expression.Constant(Value) 
        ), 
        param); 
       // Build the expression and return it 
       return (filterExpression); 
      } 

編輯:添加更多的信息

或者,有沒有更好的辦法做到的還是?目前.Where(約束)工作得很好,其中約束是類型Expression>。我怎麼辦(約束1或約束2)(約束N'th)

在此先感謝!

回答

9

問題是您在方法OrExpressions中創建的表達式會重用這兩個表達式的主體。這些實體將包含對FilterExpression中定義的自己的ParameterExpression的引用。

修復方法是重寫左側和右側部分以使用新的ParameterExpression。或者一起傳遞原始的ParameterExpression。這不是因爲兩個ParameterExpression具有相同的名稱,而是它們表示相同的參數。

+0

謝謝!要去嘗試,現在通過相同的參數 – ccook 2009-01-04 22:25:34

+0

你我的朋友,是驚人的:) – ccook 2009-01-04 22:30:21

2

我不確定這裏的適當術語,但基本上表達式參數即使具有相同的名稱也不是等同的。

這意味着,

var param1 = Expression.Parameter(typeof(T), "item"); 
var param2 = Expression.Parameter(typeof(T), "item"); 

param1 != param2 

參數1和參數將不會是相同的事情,如果在表達式中使用。

處理此問題的最佳方法是先爲表達式創建一個參數,然後將其傳遞給需要該參數的所有幫助器函數。

編輯:此外,如果您嘗試動態撰寫LINQ中的where子句,您可以試試PredicateBuilder

+0

謝謝:)我修改了方法相同的參數,以輔助的方法來傳遞,所有又是很好的。我期待到PredicateBuilder有希望乾淨的東西了 – ccook 2009-01-04 22:37:27

4

正如已經建議,here你可以找到這個非常漂亮的(工作)代碼

public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) 
{ 
    var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>()); 
    return Expression.Lambda<Func<T, bool>>(Expression.Or(expr1.Body, invokedExpr), expr1.Parameters); 
} 

,你可以適應您的需求,它不依賴(恕我直言)到LINQ。

1

Fabrizio的解決方案也出現在我身上,但由於我試圖將兩個表達式作爲linq 2 sql查詢來執行,我認爲它會在內存中而不是sql服務器中執行。

我寫道 - Linq-To-Sql認識到調用是lambda表達式,因此仍然會生成優化的sql。

2

對於那些,誰通過搜索引擎找到了這個網頁,並要使用的PredicateBuilder距離Ben &喬阿爾巴哈利,看出來,因爲它不與實體框架工作。

嘗試this fixed version代替。