为何此处使用Expression而非Func?结合代码示例解析疑问
关于
Expression<Func<...>> vs Func<...>在你的场景中的意义 首先直接给你结论:在你当前直接编译表达式并立即执行的用法里,两者的性能差异确实非常微小,甚至大部分场景下可以忽略不计——但其实你有点用错了Expression的核心价值,咱们慢慢说:
1. 你当前用法下的性能对比
你的代码里是把Expression<Func<Person, string>>调用Compile()转换成委托后立即执行,这种情况下:
- 第一次调用
Compile()时会有额外的开销:.NET需要把表达式树解析、生成IL代码、创建委托实例,这一步比直接使用Func<...>要慢一点; - 如果重复调用同一个
Expression实例,你可以缓存编译后的委托(比如把它存在一个变量里重复用),那后续的性能就和直接用Func差不多了,但还是会有第一次的编译成本; - 而直接用
Func<Person, string>的话,委托是提前编译好的,没有额外的解析/编译步骤,调用性能会略优一点点。
所以你看到的“微小性能提升”的说法可能是指缓存了编译后的委托的场景,但如果是每次都重新编译(像你代码里那样每次调用StartsWithA都编译一次),那Expression反而会更慢一点。
2. Expression的真正价值:可解析性
你现在的用法其实只是把Expression当成了Func的“绕弯写法”,但Expression的核心优势根本不是性能,而是它是可解析的表达式树——你可以读取它的结构,知道它访问的是哪个属性、做了什么操作,甚至修改它,然后转换成其他形式的代码。
举几个实际的例子:
- 如果你想扩展你的方法,比如返回“检查的是哪个属性”,用
Expression的话可以解析出访问的是Name还是Nickname,而Func做不到,因为它是编译后的黑盒代码; - 像EF Core这样的ORM框架,就是用
Expression来把LINQ查询转换成SQL语句的:它解析你写的p => p.Name.StartsWith("a")表达式树,然后生成对应的WHERE Name LIKE 'a%'SQL; - 你还可以动态修改表达式树,比如把
StartsWith("a")改成StartsWith("b"),再编译成委托执行,这也是Func做不到的。
3. 回到你的场景:该用哪个?
如果你的需求只是执行一个属性访问的委托,检查字符串开头,那直接用Func<Person, string>更合适:
public bool StartsWithA(Person p, Func<Person, string> f) { return f(p).ToLower().StartsWith("a"); }
这样代码更直接,没有额外的编译开销,性能也更好。
只有当你需要分析、修改表达式结构,或者把表达式转换成其他形式时,才需要用Expression<Func<Person, string>>。
内容的提问来源于stack exchange,提问作者Avrohom Yisroel
相关产品推荐
相关产品推荐

