Search code examples
c#expression-trees

How to convert Expression<Func<TSource,TKey>> and TKey to Expression<Func<TSource,bool>>?


IQueryable.OrderBy receives a key selector expression Expression<Func<TSource,TKey>>. IQueryable.Single receives a comparison expression Expression<Func<TSource,bool>>.

Can I convert an Expression<Func<TSource,TKey>> and a TKey value into an Expression<Func<TSource,bool>>? For example, if I have the key selector expression x => e => e.Id, I want the comparison expression x => e => e.Id == value.

I wrote this method:

public Expression<Func<TEntity, bool>> KeyComparator(TKey key) =>
            Expression.Lambda<Func<TEntity, bool>>(Expression.Equal(KeySelector, Expression.Constant(key)))

This makes the compiler happy. I can write stuff like someQueryable.Single(KeyComparator(key)). But when it runs I get this error:

The binary operator Equal is not defined for the types 'System.Func`2[TSource,System.Int32]' and 'System.Int32'.

...where TSource is my actual class name. That seems to say that equality comparison is not defined for int and int. Huh?


Solution

  • So you want to convert the expression to be like a predicate that compares the TKey (what the expression evaluates to) to another given TKey.

    You should get the Body of the lambda expression, which is what your code is missing, to create a == expression. You cannot compare the lambda expression itself with a TKey. The Body refers to everything on the right of => of the lambda.

    You should also include the original lambda's parameters, when putting the new == expression into a Expression.Lambda.

    public static Expression<Func<TSource, bool>> Convert<TSource, TKey>(
        Expression<Func<TSource, TKey>> expr,
        TKey key
    ) => Expression.Lambda<Func<TSource, bool>>(
            Expression.Equal(expr.Body, Expression.Constant(key)),
            expr.Parameters
        );
    

    Example:

    Console.WriteLine(Convert((String s) => s.Length, 1));
    // s => (s.Length == 1)