Комбинируя два выражения (Выражение <Func <T, bool>>)

Ключевое слово global полезно только для изменения или создания глобальных переменных в локальном контексте, хотя создание глобальных переменных редко считается хорошим решением.

def bob():
    me = "locally defined"    # Defined only in local context
    print me

bob()
print me     # Asking for a global variable

Вышеупомянутое даст вам:

locally defined
Traceback (most recent call last):
  File "file.py", line 9, in <module>
    print me
NameError: name 'me' is not defined

Хотя, если вы используете оператор global, переменная станет доступной «вне» области действия функции, фактически становясь глобальной переменной.

def bob():
    global me
    me = "locally defined"   # Defined locally but declared as global
    print me

bob()
print me     # Asking for a global variable

So приведенный выше код даст вам:

locally defined
locally defined

Кроме того, из-за характера python вы также можете использовать global для объявления функций, классов или других объектов в локальном контексте. Хотя я бы советовал против этого, поскольку он вызывает кошмары, если что-то пошло не так или требует отладки.

232
задан andy 26 June 2009 в 14:04
поделиться

2 ответа

Ну, можно использовать Expression.AndAlso / OrElse и т.д. для объединения логических выражений, но проблемой являются параметры; Вы работаете с тем же ParameterExpression в expr1 и expr2? Если так, это легче:

var body = Expression.AndAlso(expr1.Body, expr2.Body);
var lambda = Expression.Lambda<Func<T,bool>>(body, expr1.Parameters[0]);

Это также работает хорошо для отрицания единственной операции:

static Expression<Func<T, bool>> Not<T>(
    this Expression<Func<T, bool>> expr)
{
    return Expression.Lambda<Func<T, bool>>(
        Expression.Not(expr.Body), expr.Parameters[0]);
}

Иначе, в зависимости от поставщика LINQ, Вы могли бы быть в состоянии объединить их с Invoke:

// OrElse is very similar...
static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> left,
    Expression<Func<T, bool>> right)
{
    var param = Expression.Parameter(typeof(T), "x");
    var body = Expression.AndAlso(
            Expression.Invoke(left, param),
            Expression.Invoke(right, param)
        );
    var lambda = Expression.Lambda<Func<T, bool>>(body, param);
    return lambda;
}

Где-нибудь, у меня есть некоторый код, который переписывает дерево выражений, заменяющее узлы для устранения необходимости Invoke, но это довольно длинно (и я не могу помнить, где я оставил его...)

<час>

Обобщенная версия, которая выбирает самый простой маршрут:

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);
}

Запуск с .net 4.0. Существует класс ExpressionVistor, который позволяет Вам создавать выражения, которые являются сейфом EF.

    public static Expression<Func<T, bool>> AndAlso<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var parameter = Expression.Parameter(typeof (T));

        var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
        var left = leftVisitor.Visit(expr1.Body);

        var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
        var right = rightVisitor.Visit(expr2.Body);

        return Expression.Lambda<Func<T, bool>>(
            Expression.AndAlso(left, right), parameter);
    }



    private class ReplaceExpressionVisitor
        : ExpressionVisitor
    {
        private readonly Expression _oldValue;
        private readonly Expression _newValue;

        public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
        {
            _oldValue = oldValue;
            _newValue = newValue;
        }

        public override Expression Visit(Expression node)
        {
            if (node == _oldValue)
                return _newValue;
            return base.Visit(node);
        }
    }
306
ответ дан jeuxjeux20 23 November 2019 в 03:36
поделиться

Joe Albahari (Автор C# 3.0 вкратце и LINQPad) записал утилиту под названием PredicateBuilder, который может привыкнуть к И и ИЛИ функционирует вместе.

http://www.albahari.com/nutshell/predicatebuilder.aspx

, В то время как это работает над функциями, это - открытый исходный код, таким образом, можно проверить его и видеть, как это работает.

30
ответ дан Cameron MacFarland 1 September 2019 в 19:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: