0

Consider expression tree below,

var parameter = Expression.Parameter(typeof(Customer), "b");
var property = Expression.Property(parameter, "FirstName");
var abc = new string[] { "a", "b" };
MethodInfo contains = typeof(Enumerable)
    .GetMethods(BindingFlags.Static | BindingFlags.Public)
    .Where(x => x.Name.Contains(nameof(Enumerable.Contains)))
    .Single(x => x.GetParameters().Length == 2)
    .MakeGenericMethod(property.Type);
var body = Expression.Call(contains, Expression.Constant(abc), property);

when we view this code in into debug we see the query generated by the body (variable) is:

.Call System.Linq.Enumerable.Contains(
    .Constant<System.String[]>(System.String[]),
    $b.FirstName)

and when we inspect the where in (var results = customers.Where(x => abc.Contains(x.FirstName)).ToList();) we get this:

.Call System.Linq.Enumerable.Contains(
    .Constant<Program+<>c__DisplayClass0_0>(Program+<>c__DisplayClass0_0).abc,
    $x.FirstName)

How do you add the abc like in the where in the expression tree ?

Notes abc is: var abc = new string[] { "a", "b" } (see code above)

Zulander
  • 648
  • 1
  • 10
  • 22

1 Answers1

0

You are almost there. Add this:

var lambda = Expression.Lambda(body, parameter);
// Displays as:
// b => value(System.String[]).Contains(b.FirstName)

var compiled = (Func<Customer, bool>)lambda.Compile();

You can test it with:

var cust = customers.Where(compiled).ToList();
// I get the expected result with some test data.

Note: the expression above may look awkward, but this is due to the fact that the expression captures the local variable in a compiler generated class named <>c__DisplayClass0_0.

See this answer form user295190 to the question What are 'closures' in .NET?

You cannot see this compiler generated code in your expression, because it is probably created when being compiled (call to Compile()).

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188