简介
在. net中,表达式树是一种类似树的数据结构,其中每个节点都是表达式,例如,比如方法调用和 x < y 这样的二元运算等。
- 您可以编译和运行由表达式树表示的代码。
- 它允许您修改可执行代码、在各种数据库中执行LINQ查询以及动态创建动态查询。
创建表达式树
c#或Visual Basic编译器基于匿名lambda表达式创建表达式树,但是您也可以使用System.Linq.Expressions名称空间手动创建表达式树。
1.使用Lambda表达式创建表达式树
当你将一个lambda表达式赋给一个类型的Expression<TDelegate>变量时,编译器会释放代码来创建一个表达式树,它代表lambda表达式。
- c#编译器仅从单行lambdas生成表达式树。
- 它无法解析语句多行lambdas。
在这个例子中,c#编译器创建了一个表达式树,它表示lambda表达式val => val < 10。
Expression<Func<int, bool>> expression = val => val < 10;
var cResults = expression.Compile();
2.使用API创建表达式树
您可以使用 Expression 类,该类包含创建特定类型的表达式树节点的静态工厂方法。下面的示例手工构建lambda表达式val => val < 10的表达式树。
ParameterExpression numParam = Expression.Parameter(typeof(int), "val");
ConstantExpression ten = Expression.Constant(10, typeof(int));
BinaryExpression numLessThanTen = Expression.LessThan(numParam, ten);
Expression<Func<int, bool>> expression =
Expression.Lambda<Func<int, bool>>(
numLessThanTen,
new ParameterExpression[] { numParam });
var eResults = expression.Compile();
怎么使用
1.Getter/Setter Expression
属性使类能够公开获取和设置值的公共方法,同时隐藏实现或验证代码。
- get属性访问器用于返回属性值。
- 设置属性访问器用于分配新值。
您还可以使用Expression API获取/设置属性。下面是一个简单的Employee类,它包含两个属性。
public class Employee
{
public string Name { get; set; }
public DateTime BirthDate { get; set; }
}
以下的类包含使用expression api的getter / setter的实现
public static class ExpressionUtils
{
public static Action<TEntity, TProperty> CreateSetter<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> property)
{
PropertyInfo propertyInfo = ExpressionUtils.GetProperty(property);
ParameterExpression instance = Expression.Parameter(typeof(TEntity), "instance");
ParameterExpression parameter = Expression.Parameter(typeof(TProperty), "param");
var body = Expression.Call(instance, propertyInfo.GetSetMethod(), parameter);
var parameters = new ParameterExpression[] { instance, parameter };
return Expression.Lambda<Action<TEntity, TProperty>>(body, parameters).Compile();
}
public static Func<TEntity, TProperty> CreateGetter<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> property)
{
PropertyInfo propertyInfo = ExpressionUtils.GetProperty(property);
ParameterExpression instance = Expression.Parameter(typeof(TEntity), "instance");
var body = Expression.Call(instance, propertyInfo.GetGetMethod());
var parameters = new ParameterExpression[] { instance };
return Expression.Lambda<Func<TEntity, TProperty>>(body, parameters).Compile();
}
public static PropertyInfo GetProperty<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> expression)
{
var member = GetMemberExpression(expression).Member;
var property = member as PropertyInfo;
if (property == null)
{
throw new InvalidOperationException(string.Format("Member with Name '{0}' is not a property.", member.Name));
}
return property;
}
private static MemberExpression GetMemberExpression<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> expression)
{
MemberExpression memberExpression = null;
if (expression.Body.NodeType == ExpressionType.Convert)
{
var body = (UnaryExpression)expression.Body;
memberExpression = body.Operand as MemberExpression;
}
else if (expression.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpression = expression.Body as MemberExpression;
}
if (memberExpression == null)
{
throw new ArgumentException("Not a member access", "expression");
}
return memberExpression;
}
}
Setter
可以使用CreateSetter方法设置指定对象的属性值。
var setterNameProperty = ExpressionUtils.CreateSetter<Employee, string>(x => x.Name);
var setterBirthDateProperty = ExpressionUtils.CreateSetter<Employee, DateTime>(x => x.BirthDate);
Employee emp = new Employee();
setterNameProperty(emp, "John");
setterBirthDateProperty(emp, new DateTime(1990, 6, 5));
Console.WriteLine("Name: {0}, DOB: {1}", emp.Name, emp.BirthDate);
Getter
可以使用CreateGetter方法获取指定对象的属性值。
var getterNameProperty = ExpressionUtils.CreateGetter<Employee, string>(x => x.Name);
var getterBirthDateProperty = ExpressionUtils.CreateGetter<Employee, DateTime>(x => x.BirthDate);
Employee emp1 = new Employee()
{
Name = "John",
BirthDate = new DateTime(1990, 6, 5)
};
var name = getterNameProperty(emp1);
var birthDate = getterBirthDateProperty(emp1);
Console.WriteLine("Name: {0}, DOB: {1}", name, birthDate);