3

Everybody loves the LinqKit library by Joe Albahari, and its PredicateBuilder.

However, it has a drawback due to the usage of Expression<> : Expression needs to be compiled, which takes a lot of time when you use it oftenly. In some of my treatments, I noticed using a profiler than more of 50% of the processing time of my operations seems to be lost in expression's compilation.

For Linq to SQL, the compilation phase of the expression is mandatory and I perfectly understand why LinqKit use it, but for Linq to Objects, working from start to end with a simple Func should perfectly work.

But obviously, if you do so you will lose the benefit of the nice syntax of PredicateBuilder and its combination operators.

Giving for example:

public Func<Thing, bool> WherePredicate()
{
    var func = new Func<Thing, bool>(f => f.MyTest);

    if (something)
    {
        func = f => f.MyOtherTest && func(f);
    }

    return func;
}

Instead of :

public Func<Thing, bool> WherePredicate()
{
    var func = PredicateBuilder.New<Thing>(true);

    func = func.And(f => f.MyTest);

    if (something)
    {
        func = func.And(f => f.MyOtherTest);
    }

    return func;
}

Of course real world examples are much more complicated of the simple predicate above.

I would like to know if there is one easy solution that allows to combine advantages of each approach, for example using another library than LinqKit that works with Func<> instead of Expression> but with the same syntax.

AFract
  • 8,868
  • 6
  • 48
  • 70
  • 2
    *Everybody loves the LinqKit* no true ... I even doesn't know it ... https://dotnetfiddle.net/lJ3TyC ? – Selvin Aug 21 '19 at 12:35
  • 1
    @Selvin crude solution, but perfectly working ! I would just add "public static Func New(bool start) => p => start;" to make it complete in regard of my example :). – AFract Aug 21 '19 at 12:57
  • 1
    you may also use original solution and compile it only once [like `var func = WherePredicate().Compile()` and then use `func` instead `WherePredicate()`](https://dotnetfiddle.net/VX0S1y) – Selvin Aug 21 '19 at 12:57
  • @Selvin : Of course, if it was possible it could also be a nice option. But the calls to the methods that builds predicates are nested in services, there are several usages of PredicateBuilder, the conditions ("something" in my sample) that are used to generate the predicates are never the same... Etc. So it's difficult to compile it only once and to "remember" it for future use. – AFract Aug 21 '19 at 13:07
  • @Selvin : I just seen your edit on your previous comment. Calling explicitly Compile would not change anything, as you can see "WherePredicate()" are already both returning a Func, in both cases Expression is hidden inside and computed once. And as I said I have several case when I will have to create new predicates instances in different contexts, so the predicate building operation itself requires to be more efficient. – AFract Aug 21 '19 at 14:13
  • 2
    Just realize that composing `Func` is inefficient compared to composing `Expression` as you are building increasingly nested lambda method calls instead of a flat expression body e.g. you have `p => (p => (p => true)(p) && (f => f.MyTest)(p))(p) && (f => f.MyOtherTest)(p)` as opposed to `p => (true && p.MyTest) && p.MyOtherTest` (PS The latest LINQKit eliminates the unneeded initializer (`true && ` or `false || `)). – NetMage Aug 21 '19 at 22:32
  • @NetMage > very good remark, especially for complex predicates ! I missed that too. This is also another interesting reason to search an alternative. – AFract Aug 22 '19 at 07:10

0 Answers0