代码之家  ›  专栏  ›  技术社区  ›  aybe

如何将Expression<Func<T>>和Expression<Func<T,float>>组合到Expression<Func<float>>?

  •  0
  • aybe  · 技术社区  · 8 年前

    我正在尝试合并 expr1 expr2 生成 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 回复  |  直到 8 年前
        1
  •  2
  •   Servy    8 年前

    基本上,你要做的是合成两个表达式。 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);
    }
    

    通过使用上述方法泛化代码,可以确保代码正常工作 不管 而不是编写一种方法,对两个表达式中可以或不能包含的内容进行假设,或者以不同的方式处理一系列不同的情况。