如何结合Expression< Func< T>和表达式< Func< T,float>.表达式< Func< float&gt ;? [英] How to combine Expression<Func<T>> and Expression<Func<T,float>> to Expression<Func<float>>?

查看:68
本文介绍了如何结合Expression< Func< T>和表达式< Func< T,float>.表达式< Func< float&gt ;?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试结合 expr1 expr2 来生成 Expression< Func< float>> :

I am trying to combine expr1 and expr2 to produce an 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 .

While the call to expr3 does work, its .Body property cannot be casted as MemberExpression.

这是一个手工制作的表达式和 expr3 的调试字符串,显然它们是不同的:

Here are the debug strings of a manually crafted expression and expr3, obviously they're different:

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

问题是:

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

What is the correct way to make expr3 a MemberExpression instead of a LambdaExpression ?

我要实现的目标:

我想传递类似()=>的表达式._modelRgb.R 指向方法的 ColorComponent ,在这种方法中,我想为其成员中的一些成员构建大量表达式.

I'd like to pass expressions like () => _modelRgb.R that points to a ColorComponent to a method, and in this method I'd like to build numerous expression to some of its members.

推荐答案

您在这里要做的根本是组成两个表达式.此处是一种显示方法的解决方案,尽管要使第一个表达式没有参数,而不是一个参数,需要一些调整.

What you're fundamentally trying to do here is to compose two expressions. Here is a solution showing how to do that, although it requires a bit of adapdation in order to have the first expression have no parameters, rather than one parameter.

经过修改的 Compose 方法如下所示:

The adapted Compose method would look like this:

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 方法,而无需进行任何修改:

This would use the same Replace method as the linked question, without needing any adaptation:

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);
}

通过使用上述方法对代码进行泛化,可以确保代码无论使用哪种表达式都可以正常工作,而不是编写一种对可能存在或不能存在的条件进行假设的方法要么表达,要么以不同的方式处理一堆不同的情况.

By generalizing the code using the above methods you ensure that the code will work regardless of the contents of either expression, rather than writing a method that makes assumptions about what can or can't be in either expression, or to handle a bunch of different cases differently.

这篇关于如何结合Expression&lt; Func&lt; T&gt;和表达式&lt; Func&lt; T,float&gt;.表达式&lt; Func&lt; float&gt ;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆