Expression.Or, параметр 'item' находится вне области видимости
-
03-07-2019 - |
Вопрос
Я пытаюсь написать статическую функцию или два выражения, но получаю следующую ошибку:
Параметр 'item' находится вне области действия.
Описание: необработанное исключение произошло во время исполнения текущий веб-запрос. Пожалуйста, просмотрите трассировка стека для получения дополнительной информации о ошибка и откуда она возникла код. Р>
Сведения об исключении: 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'd происходят из метода ниже, которые выполняются просто отлично. если есть лучший способ или результаты, я все уши. Кроме того, я не знаю, сколько их было или заранее.
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 ')
Заранее спасибо!
Решение
Проблема в том, что выражение, которое вы создаете в методе OrExpressions, повторно использует тело двух выражений. Эти тела будут содержать ссылки на свои собственные ParameterExpression, которые были определены в FilterExpression.
Исправление будет состоять в том, чтобы переписать левую и правую части, чтобы использовать новое выражение ParameterExpression. Или передать оригинальное выражение ParameterExpression. Не потому, что два 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);
}
который вы можете адаптировать к вашим потребностям и который не привязан (IMHO) к LINQ.
Я не уверен насчет правильных терминов, но в основном параметры выражения не эквивалентны, даже если они имеют одинаковые имена.
Это означает, что
var param1 = Expression.Parameter(typeof(T), "item");
var param2 = Expression.Parameter(typeof(T), "item");
param1 != param2
param1 и param2 не будут одинаковыми при использовании в выражении.
Лучший способ справиться с этим - сначала создать один параметр для своего выражения, а затем передать его всем вспомогательным функциям, которым нужен этот параметр.
РЕДАКТИРОВАТЬ: Кроме того, если вы пытаетесь динамически составлять предложения where в LINQ, вы можете указать PredicateBuilder .
Для тех, кто нашел эту страницу поисковой системой и собирается использовать PredicateBuilder от Ben & Joe Albahari , будьте внимательны, поскольку он не работает с Entity Framework .
Попробуйте эту исправленную версию .
Решение Фабрицио также пришло мне в голову, но, поскольку я пытался объединить два выражения, которые будут выполняться как запрос sql linq 2, я думал, что он будет выполняться в памяти, а не на сервере sql.
Мне написали - Linq-To-Sql распознает, что вызов имеет лямбда-выражение и, таким образом, все еще производит оптимизированный sql.