我正在阅读有关表达式树功能以及如何使用lambda表达式创建委托。我仍然无法理解它在什么情况下是有用的,我应该在什么样的现实世界中使用它。
答案 0 :(得分:12)
表达式树的主要用途是用于进程外LINQ提供程序,例如LINQ to SQL。
当你写这样的东西时:
var query = people.Where(x => x.Age > 18)
.Select(x => x.Name);
那些lambda表达式可以 转换为委托,然后可以执行(因为它们在LINQ to Object中)或它们可以转换为表达式树,这可以由查询源进行分析并相应地采取行动(例如,通过将它们转换为SQL,Web服务调用等)。不同之处在于表达式树将代码表示为 data 。如果有必要,可以将它们编译成代理,但通常(在LINQ中无论如何)它们从不直接执行 - 只是检查以找出它们包含的逻辑。
表达式树也在动态语言运行时中广泛使用,它们表示在评估动态表达式时应执行的代码。表达式树非常适合这种情况,因为它们可以被组合并再次分解,并且在它们被编译之后,得到的IL被JIT编译为正常。
大多数开发人员永远不需要使用表达式树API,尽管它有一些其他用途。
答案 1 :(得分:5)
除了LINQ之外,另一个非常简单的用例是提取属性的名称和值。我在一个流畅的API中使用它来验证数据传输对象。传递一个lambda参数来定义名称和值比使用名称的第二个字符串参数更安全,并且冒着开发人员错误的风险。
这是一个例子(减去所有安全检查和其他内务管理):
public Validator<T> Check<T>(Expression<Func<T>> expr) {
// Analyse the expression as data
string name = ((MemberExpression) expr.Body).Member.Name;
// Compile and execute it to get the value
T value = (expr.Compile())();
return new Validator<T>(name, value);
}
使用示例:
Check(() => x.Name).NotNull.MinLength(1);
Check(() => x.Age).GreaterThan(18);
答案 2 :(得分:4)
我使用表达式树来建立一个空安全评估器:
string name = myObject.NullSafeEval(x => x.Foo.GetBar(42).Baz.Name, "Default");
此方法分析并重写表达式树,以便在每个属性或方法调用Name
的“路径”之前插入空检查。如果在此过程中遇到null,则返回默认值。
请参阅实施here
表达式树也常用于通过在字符串中对其名称进行硬编码来避免引用属性:
private string _foo;
public string Foo
{
get { return _foo; }
set
{
_foo = value;
OnPropertyChanged(() => Foo);
// Rather than:
// OnPropertyChanged("Foo");
}
}
static string GetPropertyName<T>(Expression<Func<T>> expr)
{
var memberExpr = expr.Body as MemberExpression;
if (memberExpr == null)
throw new ArgumentException("expr", "The expression body must be a member expression");
return memberExpr.Member.Name;
}
protected void OnPropertyChanged<T>(Expression<Func<T>> expr)
{
OnPropertyChanged(GetPropertyName(expr));
}
这可以启用编译时检查和名称重构