Expression.Or, параметр «элемент» не входит в область действия

Я пытаюсь написать статическую функцию для двух выражений или двух, но получаю следующую ошибку:

Параметр «элемент» не входит в область действия.

Описание: во время выполнения текущего веб-запроса возникло необработанное исключение. Пожалуйста, просмотрите трассировку стека для получения дополнительной информации об ошибке и о том, где она возникла в коде.

Сведения об исключении: System.InvalidOperationException: параметр «элемент» не входит в область действия.

метод:

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(constraint) отлично работает там, где ограничение имеет тип Expression>. Как я могу сделать, где (ограничение1 или ограничение2) (до ограничения n-го)

Заранее спасибо!


person ccook    schedule 04.01.2009    source источник


Ответы (5)


Проблема в том, что выражение, которое вы создаете в методе OrExpressions, повторно использует тело двух выражений. Эти тела будут содержать ссылки на собственное выражение ParameterExpression, определенное в выражении фильтра.

Исправление состояло бы в том, чтобы переписать левую и правую части, чтобы использовать новое ParameterExpression. Или передать исходное ParameterExpression. Это не потому, что два ParameterExpression имеют одно и то же имя, они представляют один и тот же параметр.

person Jb Evain    schedule 04.01.2009
comment
Спасибо! Сейчас попробую передать тот же параметр - person ccook; 05.01.2009
comment
Ты, мой друг, прекрасен :) - person ccook; 05.01.2009

Как уже было сказано, здесь вы можете найти этот очень хороший (рабочий) код

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.

person Fabrizio C.    schedule 05.01.2009
comment
Будьте осторожны, так как этот код не работает для Entity Framework. Смотрите мой ответ для фиксированной версии. - person Alex Che; 25.09.2012

Я не уверен в правильных терминах здесь, но в основном параметры выражения не эквивалентны, даже если они имеют одно и то же имя.

Что означает, что

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

param1 != param2

param1 и param2 не будут одним и тем же при использовании в выражении.

Лучший способ справиться с этим — создать один параметр заранее для вашего выражения, а затем передать его всем вспомогательным функциям, которым нужен этот параметр.

РЕДАКТИРОВАТЬ: Кроме того, если вы пытаетесь динамически составлять предложения where в LINQ, вы можете указать PredicateBuilder попытка.

person Cameron MacFarland    schedule 04.01.2009
comment
Спасибо :) Я переработал метод, чтобы передать тот же параметр в методы помощника, и все снова хорошо. Я изучаю PredicateBuilder, чтобы, надеюсь, все исправить. - person ccook; 05.01.2009
comment
Будьте осторожны, так как PredicateBuilder от Ben&Joe Albahari не работает для Entity Framework. Смотрите мой ответ для фиксированной версии. - person Alex Che; 25.09.2012

Для тех, кто нашел эту страницу с помощью поисковой системы и собирается использовать PredicateBuilder от Ben&Joe Albahari, будьте осторожны, так как он не работает с Entity Framework.

Вместо этого попробуйте эту фиксированную версию.

person Alex Che    schedule 25.09.2012

Решение Фабрицио также пришло мне в голову, но поскольку я пытался объединить два выражения, которые будут выполняться как SQL-запрос linq 2, я думал, что оно будет выполняться в памяти, а не на SQL-сервере.

Мне написали - Linq-To-Sql распознает, что вызов является лямбда-выражением, и, таким образом, по-прежнему создает оптимизированный sql.

person Tahir Hassan    schedule 11.03.2010