Вам необходимо изменить аргументы Func<T, DateTime>
на Expression<Func<T, DateTime>>
и включить их в желаемое выражение.
К сожалению, ни компилятор C #, ни BCL не помогают с более поздней задачей (составление выражения из других выражений).Существуют сторонние пакеты, такие как LinqKit , NeinLinq и т. Д., Которые решают эту проблему, поэтому, если вы планируете интенсивно использовать композицию выражений, вы можете рассмотреть возможность использования одной из этих библиотек.
Но принцип один и тот же.В какой-то момент пользовательский ExpressionVisitor
используется для замены частей исходного выражения другими выражениями.Например, для таких простых сценариев я использую лямбда-выражение времени компиляции с дополнительными параметрами, используемыми в качестве заполнителей, которые затем заменяются фактическими выражениями почти так же, как string.Replace
.
Для этого я использую следующий вспомогательный метод для замены параметра лямбда-выражения другим выражением:
public static partial class ExpressionUtils
{
public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
{
return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
}
class ParameterReplacer : ExpressionVisitor
{
public ParameterExpression Source;
public Expression Target;
protected override Expression VisitParameter(ParameterExpression node)
=> node == Source ? Target : base.VisitParameter(node);
}
}
, и рассматриваемый метод может выглядеть следующим образом:
public static Expression<Func<T, bool>> IsPeriodActive<T>(
DateTime checkPeriodStart,
DateTime checkPeriodEnd,
Expression<Func<T, DateTime>> entityPeriodStart,
Expression<Func<T, DateTime>> entityPeriodEnd)
{
var entityParam = Expression.Parameter(typeof(T), "entity");
var periodStartValue = entityPeriodStart.Body
.ReplaceParameter(entityPeriodStart.Parameters[0], entityParam);
var periodEndValue = entityPeriodEnd.Body
.ReplaceParameter(entityPeriodEnd.Parameters[0], entityParam);
Expression<Func<DateTime, DateTime, bool>> baseExpr = (periodStart, periodEnd) =>
(checkPeriodEnd >= periodStart && checkPeriodEnd <= periodEnd)
|| (checkPeriodStart >= periodStart && checkPeriodEnd <= periodEnd)
|| (periodStart >= checkPeriodStart && periodStart <= checkPeriodEnd)
|| (periodEnd >= checkPeriodStart && periodEnd <= checkPeriodEnd)
|| (periodStart >= checkPeriodStart && periodStart <= checkPeriodEnd);
var periodStartParam = baseExpr.Parameters[0];
var periodEndParam = baseExpr.Parameters[1];
var expr = baseExpr.Body
.ReplaceParameter(periodStartParam, periodStartValue)
.ReplaceParameter(periodEndParam, periodEndValue);
return Expression.Lambda<Func<T, bool>>(expr, entityParam);
}
Примечаниечто вам нужно перепривязать (используя тот же вспомогательный метод ReplaceParameter
) тела переданных выражений Expression<Func<T, DateTime>>
к общему параметру, который будет использоваться в выражении результата.
Код можно упростить, добавив большевспомогательные методы, как здесь Entity Framework + DayOfWeek , но, опять же, если вы планируете использовать это часто, лучшим выбором будет использование некоторой готовой библиотеки, потому что в конце вы начнете изобретать то, что делают эти библиотеки.