如何将 Expression<Func<T>> 和 Expression<Func<T,float>> 合并为 Expression<Func<float>>?

How to combine Expression<Func<T>> and Expression<Func<T,float>> to Expression<Func<float>>?

我正在尝试结合 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 的表达式传递给一个方法,在这个方法中我想为它的一些成员构建大量表达式。

您在这里基本上要做的是组合两个表达式。 是一个展示如何做到这一点的解决方案,尽管它需要一些调整以使第一个表达式没有参数,而不是一个参数。

改编后的 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);
}

通过使用上述方法概括代码,您可以确保代码无论任何一个表达式的内容如何,​​而不是编写一个方法来假设什么可以或不能在任何一个表达式中,也不能以不同的方式处理一堆不同的情况。