Building dynamic lambda expression

dynamic expression expression-trees lambda tree

Question

I know how to build a simple lambda like x => x > 5:

int[] nbs = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };            
IEnumerable<int> result1 = nbs.Where(x => x > 5);

ParameterExpression parameter = Expression.Parameter(typeof(int), "x");
ConstantExpression constant = Expression.Constant(5);
BinaryExpression expressionBody = Expression.GreaterThan(parameter, constant);
Expression<Func<int, bool>> expression = Expression.Lambda<Func<int, bool>>(expressionBody, parameter);
IEnumerable<int> result2 = nbs.Where(expression.Compile());

But, how do I build a lambda like this p => p.Cars.Any(c => c.Horsepowers > 300)?

public class Person
{
    public string Name { get; set; }
    public List<Car> Cars { get; set; }
}

public class Car
{
    public string Make { get; set; }
    public int Horsepowers { get; set; }
}

Person p1 = new Person();
p1.Name = "Thom";
p1.Cars = new List<Car>()
{
 new Car(){Horsepowers = 100, Make = "Toyota"},
 new Car(){Horsepowers = 200, Make = "Fiat"},
 new Car(){Horsepowers = 300, Make = "Audi"},
 new Car(){Horsepowers = 400, Make = "Ferrari"}
};

Person p2 = new Person();
p2.Name = "Allen";
p2.Cars = new List<Car>()
{
 new Car(){Horsepowers = 500, Make = "McLaren"},
 new Car(){Horsepowers = 200, Make = "Volvo"},
 new Car(){Horsepowers = 300, Make = "Audi"},
 new Car(){Horsepowers = 400, Make = "Ferrari"}
};

List<Person> persons = new List<Person>();
persons.Add(p1);
persons.Add(p2);

IEnumerable<Person> res = persons.Where(p => p.Cars.Any(c => c.Horsepowers > 300));

In other words, how do I build an expression ( Expression<Func<Person, bool>> ) dynamically that I can pass as a parameter to the Where method?

1
0
9/17/2018 12:26:09 PM

Accepted Answer

To create a complex expression tree start from leaves and go up to the root. In your case you can start with building inner lambda c => c.Horsepowers > 300:

var c = Expression.Parameter(typeof(Car), "c");
var horsepower = Expression.PropertyOrField(c, "Horsepowers");
var minHorsepower = Expression.Constant(300);
var grateThen = Expression.GreaterThan(horsepower, minHorsepower);
var innerLambda = Expression.Lambda<Func<Car, bool>>(grateThen, c);

Now you can create p.Cars.Any(...) and put your inner lambda inside

var p = Expression.Parameter(typeof(Person), "p");
var cars = Expression.PropertyOrField(p, "Cars");
var any = Expression.Call(
    typeof(Enumerable), 
    nameof(Enumerable.Any), 
    new[] {typeof(Car)}, 
    cars,
    innerLambda
  );

After that build your root lambda:

var lambda = Expression.Lambda<Func<Person, bool>>(any, p);
0
9/17/2018 2:44:43 PM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow