Search code examples
c#linqlambdareflectionexpression-trees

Expression.Call on array with a custom function


I have a list of items, I want ,via expression, to filter out the items using my own custom function.

Something like this

return Items.Where(Foo)
private static bool Foo(Item item) { item.Name.Equals("...");

what i currently have

public static Expression BuildExpression(IList<Item> items) 
{
    Expression<Func<Item, bool>> expression = item => Foo(item);
    var method = (expression.Body as MethodCallExpression)?.Method;
    return Expression.Call(method, Expression.Constant(items.First());
}

this seems to work find and well for 1 item but i can't figure out how to change it to work for IList<Item>

P.s

Foo signature can be changed if needed


Solution

  • In the nutshell you need to find the Enumerable.Where<TSource>(IEnumerable<TSource>, Func<TSource,Boolean>) method. For example:

    // find the Enumerable.Where with 2 parameters using reflection
    var where = typeof(Enumerable).GetMethod(nameof(Enumerable.Where), BindingFlags.Public | BindingFlags.Static, new[]
    {
        typeof(IEnumerable<>).MakeGenericType(Type.MakeGenericMethodParameter(0)),
        typeof(Func<,>).MakeGenericType(Type.MakeGenericMethodParameter(0), typeof(bool))
    });
    
    // make generic Enumerable.Where<Item>
    var whereItem = where.MakeGenericMethod(typeof(Item));
    
    // sample data 
    IList<Item> items = new List<Item> { new() };
    // sample filter
    var filter = (Item i) => true;
    
    // create expression
    var expr = Expression.Call(whereItem, Expression.Constant(items), Expression.Constant(filter));
    
    // validate
    var enumerable = Expression.Lambda<Func<IEnumerable<Item>>>(expr).Compile()();
    

    Demo@sharplab.io

    Demo@dotnetfiddle.net with .NET Framework 4.7.1, main change:

    var where = typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
        .First(mi => mi.Name == "Where" 
              && mi.GetParameters().Length == 2);
    

    P.S.

    TBH I doubt that this would be very useful for you but without having full overview of the problem it is hard to tell.