【问题标题】:Merge two expressions of same type (without bool)合并两个相同类型的表达式(不带 bool)
【发布时间】:2016-12-18 15:54:39
【问题描述】:

我有一个方法接受表达式Expression<Func<TFoo, string>> exp

我可以像这样传递单个表达式

MyMethod(o => o.SomeStringProperty);

但现在我想组合表达式(来自两个字符串属性)并传入这个方法

我发现的所有其他例子都是Expression<Func<Foo, bool>>

我试过了

Expression<Func<TFoo, string>> fn1 = x => x.SomeStringProperty1;
Expression<Func<TFoo, string>> fn2 = x => x.SomeStringProperty2;

var body = Expression.Coalesce(fn1.Body, fn2.Body);
var lambda = Expression.Lambda<Func<TFoo, string>>(body, fn1.Parameters[0]);

但几乎每个 Expression 的函数都会抛出异常。这个怎么结合?

【问题讨论】:

  • “组合”两个表达式是什么意思?在您的示例中,您只是调用带有两个参数的方法。
  • @IvanStoev:更新了我的问题

标签: c# expression func


【解决方案1】:

在组合 lambda 表达式时,您应该确保它们绑定到结果表达式中使用的同一参数 instances

可以通过两种方式实现。

首先是使用Expression.Invoke方法:

var body = Expression.Coalesce(fn1.Body, Expression.Invoke(fn2, fn1.Parameters[0]));
var lambda = Expression.Lambda<Func<TFoo, string>>(body, fn1.Parameters[0]);

这是最简单的方法,但会为不支持调用表达式的实体框架和类似创建不支持的表达式。

第二种方法使用一个简单的参数替换助手将第二个 lambda 表达式主体重新绑定到第一个 lambda 表达式参数:

public static class ExpressionUtils
{
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
    {
        return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
    }
    class ParameterReplacer : ExpressionVisitor
    {
        public ParameterExpression Source;
        public Expression Target;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == Source ? Target : base.VisitParameter(node);
        }
    }
}

喜欢这个

var body = Expression.Coalesce(fn1.Body, 
    fn2.Body.ReplaceParameter(fn2.Parameters[0], fn1.Parameters[0]));
var lambda = Expression.Lambda<Func<TFoo, string>>(body, fn1.Parameters[0]);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 2010-10-02
    • 1970-01-01
    相关资源
    最近更新 更多