构建动态 lambda 表达式
Building dynamic lambda expression
我知道如何构建一个简单的 lambda,例如 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());
但是,我该如何构建这样的 lambda 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));
换句话说,我如何动态构建一个表达式 ( Expression<Func<Person, bool>>
),我可以将其作为参数传递给 Where 方法?
要创建一个复杂的表达式树,从叶开始向上到根。在您的情况下,您可以从构建内部 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);
现在您可以创建 p.Cars.Any(...)
并将您的内部 lambda 放入其中
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
);
之后构建你的根 lambda:
var lambda = Expression.Lambda<Func<Person, bool>>(any, p);
我知道如何构建一个简单的 lambda,例如 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());
但是,我该如何构建这样的 lambda 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));
换句话说,我如何动态构建一个表达式 ( Expression<Func<Person, bool>>
),我可以将其作为参数传递给 Where 方法?
要创建一个复杂的表达式树,从叶开始向上到根。在您的情况下,您可以从构建内部 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);
现在您可以创建 p.Cars.Any(...)
并将您的内部 lambda 放入其中
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
);
之后构建你的根 lambda:
var lambda = Expression.Lambda<Func<Person, bool>>(any, p);