【问题标题】:How can I convert a BinaryExpression to Expression<Func<T, bool>>? [duplicate]如何将 BinaryExpression 转换为 Expression<Func<T, bool>>? [复制]
【发布时间】:2017-04-01 12:48:02
【问题描述】:

我有以下简单的扩展类

public static class ExpressionOrExtension
{
    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> source, Expression<Func<T, bool>> expression)
    {
        if (source == null)
            return expression;
        return Expression.Or(source, expression);
    }
}

但是 Expression.Or 返回一个 BinaryExpression - 我怎样才能让它返回一个 Expression&lt;Func&lt;T, bool&gt;&gt; 呢?

这就是我尝试使用实体框架的方法

    public IQueryable<BookVerse> FindByVerseReferences(string bookCode, params VerseReference[] verseReferences)
    {
        Expression<Func<BookVerse, bool>> conditions = null;
        foreach(VerseReference verseReference in verseReferences ?? new VerseReference[0])
        {
            conditions = conditions.Or<BookVerse>(x =>
                    x.BookCode == bookCode
                    && x.Chapter == verseReference.Chapter
                    && x.FirstVerse <= verseReference.LastVerse
                    && x.LastVerse >= verseReference.FirstVerse);
        }
        return MyDbContext.BookVerses.Where(conditions);
    }

【问题讨论】:

    标签: c# entity-framework linq lambda expression


    【解决方案1】:

    你需要构造一个 lambda 表达式:

    var p = Expression.Parameter(typeof(T));
    return (Expression<Func<T,bool>>)Expression.Lambda(
        Expression.Or(
            Expression.Invoke(source, p)
        ,   Expression.Invoke(expression, p)
        )
    ,   p
    );
    

    Demo:

    Expression<Func<int,bool>> a = x=>x > 5;
    Expression<Func<int,bool>> b = x=>x < -5;
    var or = Or(a, b);
    var f = (Func<int,bool>)or.Compile();
    for (int i = -10 ; i <= 10 ; i++) {
        Console.WriteLine("{0} - {1}", i, f(i));
    }
    

    【讨论】:

    • 取决于 OP 使用表达式的目的,这可能会或可能不会起作用。我知道 EF 不支持这一点,其他 LINQ 提供程序也可能有问题。
    • 是的,它是实体框架。我添加了一个用例源 sn-p 以进行澄清。
    • 我认为Expression.Invoke 是不必要的,但实际上它们不是。
    【解决方案2】:

    我使用了LinqKit nuget 包并像这样实现它......

        public IQueryable<BookVerse> FindByVerseReferences(string bookCode, params VerseReference[] verseReferences)
        {
            var predicateBuilder = PredicateBuilder.New<BookVerse>();
            Expression<Func<BookVerse, bool>> predicate = null;
            foreach(VerseReference verseReference in verseReferences ?? new VerseReference[0])
            {
                Expression<Func<BookVerse, bool>> conditions = (x =>
                        x.BookCode == bookCode
                        && x.Chapter == verseReference.Chapter
                        && x.FirstVerse <= verseReference.LastVerse
                        && x.LastVerse >= verseReference.FirstVerse);
                predicate = predicateBuilder.Or(conditions);
            }
            return ObjectSpace.BookVerses.AsExpandable().Where(predicate);
        }
    

    【讨论】:

    • 如果您使用的是 LINQKit,那么整个问题没有任何意义,因为所讨论的功能是由 LINQKit 提供的。
    • 这就是为什么在答案中而不是在问题中提到了LinqKit,因为我曾经解决过这个问题:)
    • 不,你没有。问题是关于您的 Or 扩展方法,而您的“回答”与该问题没有任何共同之处。我的意思是,有问题的Or 方法仍然不起作用:)
    • 我们必须同意不同意
    • @IvanStoev 有问题的Or 方法现在可以通过调用LINQKit 的predicateBuilder.Or 来实现。因为它现在只不过是一个包装器,所以该包装器已在此答案中删除,但此答案中的代码确实显示了它是如何完成的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-05
    相关资源
    最近更新 更多