首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何将LINQ表达式合并为一个表达式?

如何将LINQ表达式合并为一个表达式?
EN

Stack Overflow用户
提问于 2009-12-17 23:27:14
回答 3查看 12.3K关注 0票数 21

我有一个表单,上面有多个字段(公司名称、邮政编码等)。其允许用户在数据库中搜索公司。如果用户在多个字段中输入值,那么我需要搜索所有这些字段。我正在使用LINQ查询数据库。

到目前为止,我已经成功地编写了一个函数,它将查看它们的输入并将其转换为表达式列表。现在,我希望将该列表转换为一个表达式,然后可以通过LINQ提供程序执行该表达式。

我最初的尝试如下所示

代码语言:javascript
复制
private Expression<Func<Company, bool>> Combine(IList<Expression<Func<Company, bool>>> expressions)
    {
        if (expressions.Count == 0)
        {
            return null;
        }
        if (expressions.Count == 1)
        {
            return expressions[0];
        }
        Expression<Func<Company, bool>> combined = expressions[0];
        expressions.Skip(1).ToList().ForEach(expr => combined = Expression.And(combined, expr));
        return combined;
    }

但是,这会失败,并显示一条异常消息,类似于"The binary operator And not defined for...“有人知道我需要做些什么来组合这些表达式吗?

编辑:更正了我忘记将and‘’ing表达式的结果一起赋给变量的那一行。谢谢你们指出这一点。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-12-17 23:32:06

编辑:在表达式树方面,Jason的答案现在比我的更完整,所以我删除了这一部分。然而,我想留下这个:

我假设您正在将这些用于Where子句...为什么不对每个表达式依次调用Where?这应该会有同样的效果:

代码语言:javascript
复制
var query = ...;
foreach (var condition in conditions)
{
    query = query.Where(condition);
}
票数 9
EN

Stack Overflow用户

发布于 2009-12-17 23:33:54

您可以结合使用Expression.AndAlsoEnumerable.Aggregate。下面是一个通用版本:

代码语言:javascript
复制
Expression<Func<T, bool>> AndAll<T>(
    IEnumerable<Expression<Func<T, bool>>> expressions) {

    if(expressions == null) {
        throw new ArgumentNullException("expressions");
    }
    if(expressions.Count() == 0) {
        return t => true;
    }
    Type delegateType = typeof(Func<,>)
                            .GetGenericTypeDefinition()
                            .MakeGenericType(new[] {
                                typeof(T),
                                typeof(bool) 
                            }
                        );
    var combined = expressions
                       .Cast<Expression>()
                       .Aggregate((e1, e2) => Expression.AndAlso(e1, e2));
    return (Expression<Func<T,bool>>)Expression.Lambda(delegateType, combined);
}

您当前的代码永远不会赋值给combined

代码语言:javascript
复制
expr => Expression.And(combined, expr);

返回一个新的Expression,它是对combinedexpr进行按位and运算的结果,但不会对combined进行变异。

票数 27
EN

Stack Overflow用户

发布于 2016-10-17 04:05:26

这里我们有一个关于组合Linq表达式的一般问题。对于这个问题,我有一个通用的解决方案。我会提供一个关于发布的具体问题的答案,尽管在这种情况下肯定不会这样做。但是,当简单的解决方案在您的情况下失败时,您可以尝试使用此方法。

首先,您需要一个由两个简单函数组成的库。它们使用System.Linq.Expressions.ExpressionVisitor动态修改表达式。关键特性是统一表达式中的参数,从而使两个同名的参数完全相同(UnifyParametersByName)。剩下的部分是用给定的表达式(ReplacePar)替换命名参数。这个库可以在github: LinqExprHelper上获得麻省理工学院的许可,但你可以很快地自己写一些东西。

该库允许使用非常简单的语法来组合复杂的表达式。您可以将内联lambda表达式与动态表达式创建和组合混合在一起,这非常有用。

代码语言:javascript
复制
    private static Expression<Func<Company, bool>> Combine(IList<Expression<Func<Company, bool>>> expressions)
    {
        if (expressions.Count == 0)
        {
            return null;
        }

        // Prepare a master expression, used to combine other
        // expressions. It needs more input parameters, they will
        // be reduced later.
        // There is a small inconvenience here: you have to use
        // the same name "c" for the parameter in your input
        // expressions. But it may be all done in a smarter way.
        Expression <Func<Company, bool, bool, bool>> combiningExpr =
            (c, expr1, expr2) => expr1 && expr2;

        LambdaExpression combined = expressions[0];
        foreach (var expr in expressions.Skip(1))
        {
            // ReplacePar comes from the library, it's an extension
            // requiring `using LinqExprHelper`.
            combined = combiningExpr
                .ReplacePar("expr1", combined.Body)
                .ReplacePar("expr2", expr.Body);
        }
        return (Expression<Func<Company, bool>>)combined;
    }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1922497

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档