Expression.Or、パラメーター 'item'はスコープ内にありません
-
03-07-2019 - |
質問
静的関数をOr 2つの式に書き込もうとしていますが、次のエラーを受け取ります:
パラメータ「item」はスコープ内にありません。
説明:未処理の例外 の実行中に発生した 現在のWeb要求。を確認してください スタックトレースの詳細については エラーとその原因 コード。
例外の詳細: System.InvalidOperationException: パラメーター 'item'はスコープ内にありません。
メソッド:
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);
}
編集:さらに情報を追加
orされている式は、以下のメソッドから来ており、うまく実行されます。より良い方法や結果があれば、私はすべて耳にします。また、どれだけの数の人が事前にオアされているかわかりません。
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);
}
編集:さらに情報を追加
別の方法として、orを実行するより良い方法はありますか?現在、.Where(constraint)は、制約がExpression&gt;型である場合に正常に機能します。 where(constraint1またはconstraint2)(制約n番目まで)を行うにはどうすればよいですか
事前に感謝します!
解決
問題は、OrExpressionsメソッドで作成しているExpressionが2つの式の本文を再利用することです。これらのボディには、FilterExpressionで定義された独自のParameterExpressionへの参照が含まれます。
修正は、新しいParameterExpressionを使用するように左右の部分を書き換えることです。または、元のParameterExpressionを渡すため。 2つのParameterExpressionが同じ名前を持っているからではなく、同じパラメーターを表します。
他のヒント
すでに提案されているように、こちらには、この非常に優れた(動作する)コードがあります
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に結び付けられていない(IMHO)。
ここでは適切な用語についてはわかりませんが、基本的に式のパラメーターは同じ名前であっても同等ではありません。
つまり、
var param1 = Expression.Parameter(typeof(T), "item");
var param2 = Expression.Parameter(typeof(T), "item");
param1 != param2
param1とparam2は、式で使用される場合、同じものにはなりません。
これに対処する最善の方法は、式の前に1つのパラメーターを作成し、そのパラメーターを必要とするすべてのヘルパー関数に渡すことです。
編集:また、LINQでwhere句を動的に作成しようとしている場合は、 PredicateBuilder を試してください。
検索エンジンでこのページを見つけて、 Ben&amp; Joe AlbahariのPredicateBuilder を使用する場合は、 Entity Frameworkでは機能しないので注意してください。
この修正版を代わりに試してください。
>Fabrizioの解決策も思いつきましたが、linq 2 sqlクエリとして実行される2つの式を組み合わせようとしたため、sqlサーバーではなくメモリで実行されると考えました。
私は書いた-Linq-To-Sqlは呼び出しがラムダ式であると認識し、最適化されたSQLを生成します。