如何组合表达式<func <t>&gt;和表达式<func <t,float>&gt;表达式<func <float>&gt;?

时间:2018-01-16 17:59:56

标签: c# lambda linq-expressions

我正在尝试合并expr1expr2来制作Expression<Func<float>>

var expr1 = (Expression<Func<ColorComponent>>)(() => _modelRgb.R);
var expr2 = (Expression<Func<ColorComponent, float>>)(s => s.Value);
var expr3 = Expression.Lambda(expr1, expr2.Parameters);

虽然对expr3的调用确实有效,但其.Body属性无法投放为MemberExpression

以下是手动制作的表达式和expr3的调试字符串,显然它们不同:

"() =>  (ColorPicker.ColorPickerWindow2)._modelRgb.R.Value"
"s => () =>  (ColorPicker.ColorPickerWindow2)._modelRgb.R"

问题是:

使expr3成为MemberExpression而不是LambdaExpression的正确方法是什么?

我想要实现的目标

我想将() => _modelRgb.R之类的表达式传递给一个方法的ColorComponent,在这个方法中,我想为它的一些成员构建多个表达式。

1 个答案:

答案 0 :(得分:2)

你从根本上想要做的是组成两个表达式。 Here是一个解决方案,展示了如何做到这一点,虽然它需要一些适应性,以使第一个表达式没有参数,而不是一个参数。

改编后的Compose方法如下所示:

public static Expression<Func<TResult>> Compose<TSource, TResult>(
    this Expression<Func<TSource>> first,
    Expression<Func<TSource, TResult>> second)
{
    return Expression.Lambda<Func<TResult>>(
        second.Body.Replace(second.Parameters[0], first.Body));
}

这将使用与链接问题相同的Replace方法,无需任何改编:

public 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 ex)
    {
        if (ex == from) return to;
        else return base.Visit(ex);
    }
}
public static Expression Replace(this Expression ex,
    Expression from,
    Expression to)
{
    return new ReplaceVisitor(from, to).Visit(ex);
}

通过使用上述方法推广代码,您可以确保代码在任何表达式的内容中都无论,而不是编写一个方法来假设什么可以或者可以&#t; t在任何一个表达中,或以不同的方式处理一堆不同的情况。