微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将两个表达式Expression <Func <T,bool >>组合成一个表达式

如何解决将两个表达式Expression <Func <T,bool >>组合成一个表达式

我要编译两个表达式:

public Expression<Func<AnyType,bool>> BuildExpression(int id,string filtreA,string filtreB)
    {
        Expression<Func<AnyType,bool>> extraExpression = null;
        Expression<Func<AnyType,bool>> expression = null;

        expression = a => a.ID == id;

        var fullExpression = expression.Body;
      
        if (!String.IsNullOrEmpty(filtreA))
        {
            extraExpression = a => a.TYPE == filtreA;
            fullExpression = Expression.AndAlso(fullExpression,extraExpression.Body);
        }
         if (!String.IsNullOrEmpty(filtreB))
        {
            extraExpression = a => a.TYPE == filtreB;
            fullExpression = Expression.AndAlso(fullExpression,extraExpression.Body);
        }
    
        expression = Expression.Lambda<Func<AnyType,bool>>(fullExpression,expression.Parameters[0]);
        }

        return expression;
    }

    //I want my final expression to be a.ID == id && a.TYPE == filtreB for example

问题是我得到以下错误 system.invalidOperationException。 Leparamètre'a'n'est pas dans laportée。。仅当输入我的一个ifs时才会发生。

有人知道我该如何处理吗?谢谢

ps:我的问题与本文相似,但似乎该解决方案不再起作用:Combining two expressions (Expression<Func<T,bool>>)

解决方法

您错过了参数替换。这对访客来说是一个棘手的问题。 为了简化您的生活,我建议使用流行的库LINQKit 并重写您的表情构建。

public Expression<Func<AnyType,bool>> BuildExpression(int id,string filtreA,string filtreB)
{
    var predicate = PredicateBuilder.New<AnyType>(true);

    predicate = predicate.And(a => a.ID == id);

    if (!string.IsNullOrEmpty(filtreA))
    {
        predicate = predicate.And(a => a.TYPE == filtreA);
    }

    if (!string.IsNullOrEmpty(filtreB))
    {
        predicate = predicate.And(a => a.TYPE == filtreB);
    }
    
    return predicate;
}
,

每个参数都是一个不同的ParameterExpression实例。如果您为每个表达式定义了不同的参数名称,此问题将更加明显;

expression = a => a.ID == id;
// ...
extraExpression = b => b.TYPE == filtreA;
// ...
extraExpression = c => c.TYPE == filtreB;

请注意,实体框架核心2.1及更早版本并不关心您的参数是否不同,并且似乎会通过.Invoke操作进行查找。但是从版本3开始,使用表达式编译器的内部重写,不支持这两种格式。因此,为什么以前的示例可能不再起作用。

交换参数表达式的表达式访问者并不复杂;

public class MapParameters:ExpressionVisitor
{
    private readonly Dictionary<ParameterExpression,ParameterExpression> mapping;
    public MapParameters(IEnumerable<ParameterExpression> before,IEnumerable<ParameterExpression> after)
    {
        this.mapping = new Dictionary<ParameterExpression,ParameterExpression>(
            before
                .Zip(after)
                .Select(p => KeyValuePair.Create(p.First,p.Second))
        );
    }
    protected override Expression VisitParameter(ParameterExpression node)
    {
        if (mapping.TryGetValue(node,out var replace))
            return replace;
        return base.VisitParameter(node);
    }
}

Expression.Lambda<Func<AnyType,bool>>(
    Expression.AndAlso(
        expression.Body,new MapParameters(
            extraExpression.Parameters,expression.Parameters
        ).Visit(extraExpression.Body)
    ),expression.Parameters);

还请注意,如果您使用它为IQuerable<T>.Where(...)构建单个表达式。您可以考虑两次调用.Where(...),这将获得相同的最终结果。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。