Ключевое слово 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
для объявления функций, классов или других объектов в локальном контексте. Хотя я бы советовал против этого, поскольку он вызывает кошмары, если что-то пошло не так или требует отладки.
Ну, можно использовать 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);
}
}
Joe Albahari (Автор C# 3.0 вкратце и LINQPad) записал утилиту под названием PredicateBuilder, который может привыкнуть к И и ИЛИ функционирует вместе.
http://www.albahari.com/nutshell/predicatebuilder.aspx
, В то время как это работает над функциями, это - открытый исходный код, таким образом, можно проверить его и видеть, как это работает.