我有一个Purchase
类
public static readonly Expression<Func<Purchase, double?>> CurrentPaidSumLambda =
p => (double?)p.Payments
.Where(pa => pa.Status == SystemConstants.PaymentStatus.Paid)
.Sum(pa => pa.Sum);
我希望将投影创建为类似PurchaseSummaryInfo
的
var ps = Db.Purchases.Select(p =>
new PurchaseSummaryInfo
{
paidSum = (double?)p.Payments
.Where(pa => pa.Status == SystemConstants.PaymentStatus.Paid)
.Sum(pa => pa.Sum) ?? 0
});
但要使用我的“预制”表达树。
能否完成,如果是的话 - 怎么做?
答案 0 :(得分:0)
我们需要Combine
方法。此方法将接受一个接受值并计算中间结果的表达式,然后接受与第一个表达式相同的输入的第二个表达式,接受中间结果作为第二个参数,然后计算新值。
public static Expression<Func<TFirstParam, TResult>>
Combine<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TFirstParam, TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], param)
.Replace(second.Parameters[1], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
作为一种实现,它依赖于将一个表达式的所有实例替换为另一个表达式的能力,这可以使用以下方法完成:
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
现在我们可以写:
var ps = Db.Purchases.Select(CurrentPaidSumLambda.Combine((p, sum) =>
new PurchaseSummaryInfo
{
paidSum = sum ?? 0
});