目录
什么是表达式树?
核心概念
1.表达式树的构建
2. 表达式树与Lambda表达式
3.解析和访问表达式树
4.动态条件查询
表达式树的优势
1.动态构建查询
2.LINQ 提供程序支持:
3.性能优化
4.元数据处理
5.代码转换和重写
适用场景
代码复杂性的权衡
什么是表达式树?
using System;
using System.Linq.Expressions;
class Program
{
static void Main()
{
// 创建一个简单的表达式:x => x + 1
ParameterExpression param = Expression.Parameter(typeof(int), "x");
BinaryExpression body = Expression.Add(param, Expression.Constant(1));
Expression> expression = Expression.Lambda>(body, param);
// 编译并执行表达式树
Func compiledExpression = expression.Compile();
int result = compiledExpression(5);
Console.WriteLine($"Result: {result}"); // 输出:Result: 6
}
}
在这个示例中,我们创建了一个简单的表达式树表示 x => x + 1,并将其编译成可执行代码。
Lambda表达式可以被编译为委托,也可以被表达式树捕获:
Expression> square = x => x * x;
此时,square不是一个委托,而是一棵描述 x * x 计算过程的树,可用于分析和转换。
表达式树可以遍历并分析其结构:
void PrintExpression(Expression exp, int level = 0)
{
Console.WriteLine(new string(' ', level * 2) + exp.NodeType + " - " + exp.Type);
if (exp is BinaryExpression bin)
{
PrintExpression(bin.Left, level + 1);
PrintExpression(bin.Right, level + 1);
}
else if (exp is ParameterExpression param)
{
Console.WriteLine(new string(' ', (level+1) * 2) + "Parameter: " + param.Name);
}
}
我们有一个 Product 类和一个产品列表。我们希望根据产品的价格动态过滤产品。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
}
class Program
{
static void Main()
{
// 创建产品列表
List products = new List
{
new Product { Name = "Laptop", Price = 1000m },
new Product { Name = "Smartphone", Price = 500m },
new Product { Name = "Tablet", Price = 300m }
};
// 动态创建表达式树来过滤价格大于 400 的产品
Func filter = CreatePriceFilter(400m);
// 使用生成的过滤器查询产品
var filteredProducts = products.Where(filter).ToList();
foreach (var product in filteredProducts)
{
Console.WriteLine($"Product: {product.Name}, Price: {product.Price}");
}
}
static Func CreatePriceFilter(decimal minPrice)
{
// 创建参数表达式
ParameterExpression param = Expression.Parameter(typeof(Product), "product");
// 创建访问属性表达式
MemberExpression priceProperty = Expression.Property(param, "Price");
// 创建常量表达式
ConstantExpression constant = Expression.Constant(minPrice);
// 创建大于运算符表达式
BinaryExpression comparison = Expression.GreaterThan(priceProperty, constant);
// 创建 lambda 表达式
Expression> lambda = Expression.Lambda>(comparison, param);
// 编译表达式树为可执行代码
return lambda.Compile();
}
}
1.设置产品列表:
2.创建表达式树:
3.应用表达式:
使用 Where 方法将生成的过滤器应用于产品列表,并输出结果。
示例1:
假设我们有一个产品列表,用户可以动态选择多个条件进行过滤,比如根据名称、价格范围或库存状态等进行筛选。我们需要在运行时根据用户输入组合这些条件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public bool InStock { get; set; }
}
class Program
{
static void Main()
{
var products = new List
{
new Product { Name = "Laptop", Price = 1000, InStock = true },
new Product { Name = "Smartphone", Price = 500, InStock = true },
new Product { Name = "Tablet", Price = 300, InStock = false }
};
// 用户可以选择动态条件
string searchName = "Laptop";
decimal? minPrice = 400;
decimal? maxPrice = null;
bool? inStock = true;
// 创建动态查询表达式
var filter = CreateDynamicFilter(searchName, minPrice, maxPrice, inStock);
// 使用生成的过滤器查询产品
var filteredProducts = products.AsQueryable().Where(filter).ToList();
foreach (var product in filteredProducts)
{
Console.WriteLine($"Product: {product.Name}, Price: {product.Price}, InStock: {product.InStock}");
}
}
static Expression> CreateDynamicFilter(string name, decimal? minPrice, decimal? maxPrice, bool? inStock)
{
// 参数表达式
var parameter = Expression.Parameter(typeof(T), "product");
Expression expression = Expression.Constant(true); // 初始谓词为 true
// 根据 name 动态创建条件
if (!string.IsNullOrEmpty(name))
{
var nameProperty = Expression.Property(parameter, "Name");
var nameValue = Expression.Constant(name);
var nameExpression = Expression.Equal(nameProperty, nameValue);
expression = Expression.AndAlso(expression, nameExpression);
}
// 根据 minPrice 创建条件
if (minPrice.HasValue)
{
var priceProperty = Expression.Property(parameter, "Price");
var minPriceValue = Expression.Constant(minPrice.Value);
var minPriceExpression = Expression.GreaterThanOrEqual(priceProperty, minPriceValue);
expression = Expression.AndAlso(expression, minPriceExpression);
}
// 根据 maxPrice 创建条件
if (maxPrice.HasValue)
{
var priceProperty = Expression.Property(parameter, "Price");
var maxPriceValue = Expression.Constant(maxPrice.Value);
var maxPriceExpression = Expression.LessThanOrEqual(priceProperty, maxPriceValue);
expression = Expression.AndAlso(expression, maxPriceExpression);
}
// 根据 inStock 创建条件
if (inStock.HasValue)
{
var stockProperty = Expression.Property(parameter, "InStock");
var stockValue = Expression.Constant(inStock.Value);
var stockExpression = Expression.Equal(stockProperty, stockValue);
expression = Expression.AndAlso(expression, stockExpression);
}
// 创建 Lambda 表达式
return Expression.Lambda>(expression, parameter);
}
}
示例2:
针对上文中只针对价格做筛选的示例,那么我们的筛选过程完全可以简化成如下表达式
var filteredProducts = products.Where(p => p.Price > 400).ToList();
总结来说,是否使用表达式树取决于你的具体需求和应用场景。在需要动态处理和复杂逻辑的情况下,表达式树提供了强大的工具支持,而在简单场景下,直接使用 Lambda 表达式或常规方法更为合适。希望这能帮助你理解表达式树的适用场景和优势!
如果你有其他问题或需要进一步的帮助,请随时告诉我。