合并两个不同类型的谓词

时间:2018-01-03 09:34:38

标签: c# expression predicate linq-expressions predicatebuilder

我已经通过地址模型(Expression<Func<Address, bool>> addressPred)构建了一个谓词。现在我想将它与Person模型的谓词(Expression<Func<Person, bool>> personPred)结合起来。模型示例如下:

public class Person
{
    public string Name { get; set; }
    public Address Address { get; set; }
}
public class Address
{
    public string StreetName { get; set; }
}

如果我做的话

addressPred = addressPred.And(a => a.StreetName == "Foo bar");

然后将其与personPred结合使用,组合谓词将具有与

相同的语句
combinedPred = combinedPred.And(a => a.Address.StreetName == "Foo bar");

combinedPredicate的类型为Person 我怎么能做到这一点?

修改 实际上,为了简单起见,模型更大,并且缩短了。我最终想要实现的是构建一次Address谓词,然后为Person创建一个具有自己条件的谓词,然后将它组合成一个谓词,其中Person谓词的Address-part来自Address谓词(Address是一个属性)人)。我想这样做的原因是因为Address可能有很多条件,我想在进行db调用之前将它用作其他谓词(Person,后来也是Company,Customer等)的一部分(对于Person,公司,客户等)
此外,combinedPred代码行仅用于显示来自地址谓词的combinedPred的等价语句。

1 个答案:

答案 0 :(得分:2)

情况是,构建的Expression<Func<Address, bool>> addressPred的地址为ParameterExpression,并且需要将表达式应用于MemberExpression。因此,我建议将ParameterExpression替换为MemberExpression,例如:

var personParameter = Expression.Parameter(typeof(Person), "person");
var addressProperty = Expression.PropertyOrField(personParameter, "Address");        
var combined = new ReplaceVisitor<Address>(addressProperty).Visit(addressPred.Body);
var result = Expression.Lambda<Func<Person, bool>>(combined, personParameter);

其中:

public class ReplaceVisitor<T> : ExpressionVisitor
{
    private readonly MemberExpression _replacement;

    public ReplaceVisitor(MemberExpression replacement)
    {
        _replacement = replacement;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node.Type.IsAssignableFrom(typeof(T))
                ? _replacement : base.VisitParameter(node);
    }
}