我如何合并两个lambda表达式,而不使用Invoke方法? [英] How can I combine two lambda expressions without using Invoke method?

查看:140
本文介绍了我如何合并两个lambda表达式,而不使用Invoke方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个lambda表达式:



表达式来; Func键< myEntity所,布尔>> E1 = I => i.FName.Contain(约翰);



 表达式来; Func键< myEntity所,布尔>> E2 = I => i.LName.Contain(史密斯); 



i型,来自于我的POCO实体,不能与调用使用。我想这些在运行时将



我想这些表达式在运行时以类似的方式结合起来:

 表达式来; Func键< myEntity所,布尔>> E3 =联合(E1,E2); 


解决方案

的问题是,你不能只是和/或他们,因为你需要重新编写内部改变参数;如果您使用。体 E1 ,而参数的从 E2 ,它不会工作 - 因为。体 E1 引用>未定义一个完全无关的参数实例。这是更加的明显的如果你使用:

 表达式来; Func键< myEntity所,布尔>> E1 = I => i.FName.Contains(约翰); 
表达式来; Func键< myEntity所,布尔>> E2 = J => j.LName.Contains(史密斯);



(注意 E1 之间的区别使用 I E2 使用Ĵ



如果我们不重写参数将它们结合起来,我们会得到无意义的:

 表达式来; FUNC< myEntity所,布尔>>合并= 
I => i.FName.Contains(约翰)及和放大器; j.LName.Contains(史密斯);



(哇....放哪儿Ĵ来自)



但?;不管的名称的参数的问题是相同的:它仍然是一个不同的参数



和因为表达式是不可变的,你可以'第•只要将它来代替



诀窍是使用一个访客重写节点,就像这样:

 使用系统;使用System.Linq.Expressions 
;

类SwapVisitor:ExpressionVisitor
{
私人只读从表达到;
公共SwapVisitor(从表达,表达于)
{
this.from =距离;
this.to =来;
}
公众覆盖式访问(Expression节点)
{
返回节点==而来?于:base.Visit(节点);
}
}

静态类节目
{
静态无效的主要()
{
表达式来; Func键< myEntity所,布尔>> E1 = I => i.FName.Contains(约翰);
表达式来; Func键< myEntity所,布尔>> E2 = I => i.LName.Contains(史密斯);

//重写E1,使用从E2的参数;与&&放大器;
VAR lambda1 = Expression.Lambda<&Func键LT; myEntity所,布尔>>(Expression.AndAlso(
新SwapVisitor(e1.Parameters [0],e2.Parameters [0])访问(E1。机身),
e2.Body),e2.Parameters);

//重写E1,使用从E2的参数; ||
VAR lambda2 = Expression.Lambda<&Func键LT; myEntity所,布尔>>(Expression.OrElse(
新SwapVisitor(e1.Parameters [0],e2.Parameters [0])访问(E1。机身),
e2.Body),e2.Parameters);
}
}


I have two lambda expressions:

Expression<Func<MyEntity, bool>> e1 = i=>i.FName.Contain("john");

and

Expression<Func<MyEntity, bool>> e2=i=>i.LName.Contain("smith");

the i type, comes from my poco entities, that can't used with invoke. I want to combine these in runtime.

I want to combine these expressions in runtime in a similar way as:

Expression<Func<MyEntity, bool>> e3 = Combine(e1,e2);

解决方案

The problem is that you can't just "and"/"or" them, because you need to re-write the internals to change the parameters; if you use the .Body from e1, but the parameter from e2, it won't work - because the .Body of e1 references a completely unrelated parameter instance that isn't defined. This is more obvious if you use:

Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john");
Expression<Func<MyEntity, bool>> e2 = j => j.LName.Contains("smith");

(note the difference between e1 using i and e2 using j)

If we combine them without rewriting the parameter, we would get the nonsensical:

Expression<Func<MyEntity, bool>> combined =
         i => i.FName.Contains("john") && j.LName.Contains("smith");

(woah.... where did j come from?)

HOWEVER; the problem is identical regardless of the name of the parameter: it is still a different parameter.

And since the expression is immutable you can't just swap it "in place".

The trick is to use a "visitor" to rewrite the nodes, like so:

using System;
using System.Linq.Expressions;

class SwapVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public SwapVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

static class Program
{
    static void Main()
    {
        Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john");
        Expression<Func<MyEntity, bool>> e2 = i => i.LName.Contains("smith");

        // rewrite e1, using the parameter from e2; "&&"
        var lambda1 = Expression.Lambda<Func<MyEntity, bool>>(Expression.AndAlso(
            new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body),
            e2.Body), e2.Parameters);

        // rewrite e1, using the parameter from e2; "||"
        var lambda2 = Expression.Lambda<Func<MyEntity, bool>>(Expression.OrElse(
            new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body),
            e2.Body), e2.Parameters);
    }
}

这篇关于我如何合并两个lambda表达式,而不使用Invoke方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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