Ключом к этому является использование ExpressionVisitor
, которое обходит заданное выражение и (необязательно, в подклассе) позволяет заменять распознанные элементы другими, указанными вами.В моем случае это было сделано для ORM (NHibernate).Вот что я использую: (я добавлю ссылки на мой ответ позже)
public class ParameterAssignAndReplacer : ExpressionVisitor
{
private readonly ParameterExpression _source;
private readonly ConstantExpression _target;
internal ParameterAssignAndReplacer(ParameterExpression source, ConstantExpression target)
{
_source = source;
_target = target;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node.Name == _source.Name ?
base.VisitConstant(_target) :
base.VisitParameter(node);
}
}
И ..
public static class ExpressionExtensions
{
public static Expression<Func<TArg2, TResult>> AssignAndReduce<TArg1, TArg2, TResult>(
this Expression<Func<TArg1, TArg2, TResult>> func,
TArg1 parameter)
{
var exprBody = func.Body;
var assignedParameter = Expression.Constant(parameter, typeof(TArg1));
exprBody = new ParameterAssignAndReplacer(func.Parameters[0], assignedParameter).Visit(exprBody);
return Expression.Lambda<Func<TArg2, TResult>>(exprBody, func.Parameters[1]);
}
}
Оба класса могут быть расширены для вашего конкретного сценария.Чтобы сделать это релевантным для кода, который вы разместили (я использую только IsDeleted
в качестве параметра для простоты):
public class SomeClass
{
Expression<Func<tbl, bool, bool>> _templateExpression =
(tbl r, bool isDeleted) => r.ID_Master == 5 && r.Year == 2008 && r.Month == 12 && r.IsDeleted == isDeleted;
public Expression<Func<tbl, bool>> Foo(bool IsDeleted)
{
return _templateExpression.AssignAndReduce(IsDeleted);
}
}
Что касается ссылок, большая часть того, что я узнал по этой теме, взята из «Выражения» Марка Гравелла отвечают [хотя многие другие пользователи помогли мне разобраться в этом :-)]