Ну, вы можете использовать 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);
}
}
Это будет хорошо.
Object[] parameters ={new Object()}; // lets say this object array is null
Class clas = Class.forName("AClass");
Object anObject = clas.newInstance();
Object[] param ={parameters};
Method someMethod = clas.getDeclaredMethod("someMethod", parameters.getClass());
someMethod.invoke(anObject, param);
Будьте осторожны со вторым параметром метода invoke. Это сам Object [], и тип аргумента вашего метода тоже Object [].
Метод Method.invoke принимает объект для получения вызова метода и массив аргументов метода. Поскольку ваш метод принимает один аргумент, указанный массив должен иметь размер один.
попробуйте создать новый массив размером 1:
someMethod.invoke(anObject, new Object[] {parameters});
Обратите внимание, что одно значение в этом массиве может быть нулевым. Это будет имитировать anObject.someMethod(null)