1

给定带有 Where 子句的查询

CollectionA.Where(a => a.Prop1 == val1 && a.Prop2 == val2)

和另一个具有类似 Where 子句但属性通过引用链接的查询。

CollectionB.Where(b => b.Reference.Prop1 == val1 && b.Reference.Prop2 == val2)

对于功能,这确实有效:

        Func<A, bool> f1 = a => a.Prop1 == val1 && a.Prop2 == val2;
        Func<B, bool> g1 = b => f1(b.Reference);

对于表达式,这不起作用:

        Expression<Func<A, bool>> f2 = a => a.Prop1 == val1 && a.Prop2 == val2;
        Expression<Func<B, bool>> g2 = b => f2(b.Reference); // <-- Method name expected.

我想使用规范在我的查询中重用表达式。

像这样:

Specification specification = new Specification(val1, val2)

CollectionA.Where(specification.ToExpression());

CollectionB.Where(specification.ToExpression(x => x.Reference));:


public class Specification 
{
    private readonly int val1;
    private readonly long val2;

    public Specification(int val1, long val2)
    {
        this.val1 = val1;
        this.val2 = val2;
    }

    public Expression<Func<A, bool>> ToExpression()
    {
        return x => x.Prop1 == val1 && x.Prop2 == val2;
    }

    public Expression<Func<B, bool>> ToExpression<B>(Expression<Func<B, A>> navigate)
    {
        // ?
    }
}

如何实现这个方法?

此外,我希望这不仅适用于二进制“和”表达式,还适用于任何表达式(即任何组合深度和参数类型)。(例如a => a.Prop1 == val1 && a.Prop2.Prop2a == val2a && a.Prop2.Prop2a == val2a)但基本上它只是实现我尝试用上面的函数 g2 做的事情。

4

1 回答 1

-1

您不能直接调用其他表达式f2(b.Reference)。并且创建一个编译和调用的表达式是徒劳的f2

您真正想要做的是编写表达式。制作一个新的表达式,表示一个表达式链接到另一个表达式。您缺少的表达式实际上只是AB如下获取的参数选择器:b => b.Reference;

这是一种方便的Compose方法(类似于这个),可以帮助将它们链接在一起。

class A
{
    public int Prop1 = 1;
    public int Prop2 = 2;
}
class B
{
    public A Reference;
}

class Program
{
    static Expression<Func<A, C>> Compose<A, B, C>(
        Expression<Func<A, B>> fAB, Expression<Func<B, C>> fBC)
    {
        var arg = Expression.Parameter(typeof(A));
        return Expression.Lambda<Func<A, C>>(
            Expression.Invoke(fBC, Expression.Invoke(fAB, arg)), arg);
    }

    static void Main(string[] args)
    {
        int val1 = 1;
        int val2 = 2;

        Func<A, bool> f1 = a => a.Prop1 == val1 && a.Prop2 == val2;
        Func<B, bool> g1 = b => f1(b.Reference);

        Expression<Func<A, bool>> f2 = a => a.Prop1 == val1 && a.Prop2 == val2;
        Expression<Func<B, A>> argSelect = b => b.Reference;
        var g2 = Compose<B, A, bool>(argSelect, f2);    

        A objA = new A();
        B objB = new B() { Reference = objA };
        var g2Compiled = g2.Compile();
        Console.WriteLine(g2Compiled.Invoke(objB));

        // Demonstrate that it's connected to our local variable
        val2 = 3;
        Console.WriteLine(g2Compiled.Invoke(objB));
    }
}

于 2020-05-16T14:10:56.123 回答