我理解lambdas和Func和Action委托。但表情 我头疼不已。
在什么情况下,你会使用表达式<Func<T>>而不是普通的旧Func<T>?
我理解lambdas和Func和Action委托。但表情 我头疼不已。
在什么情况下,你会使用表达式<Func<T>>而不是普通的旧Func<T>?
当前回答
在Krzysztof Cwalina的书(框架设计指南:可重用的。net库的约定、习惯用法和模式)中有一个更哲学的解释;
编辑非图像版本:
大多数情况下,如果你只需要运行一些代码,你就需要Func或Action。当代码在运行之前需要分析、序列化或优化时,就需要使用Expression。表达式是用来思考代码的,Func/Action是用来运行代码的。
其他回答
当您希望将函数视为数据而不是代码时,可以使用表达式。如果您想操作代码(作为数据),可以这样做。大多数情况下,如果你认为不需要表达式,那么你可能就不需要使用表达式。
这里过于简化了,但Func是一个机器,而Expression是一个蓝图。: D
在选择表达式和Func时,一个非常重要的考虑因素是IQueryable提供者,如LINQ to Entities可以“消化”你在表达式中传递的内容,但会忽略你在Func中传递的内容。关于这个主题,我有两篇博文:
更多关于表达式vs函数与实体框架和 爱上LINQ -第7部分:表达式和功能函数(最后一部分)
当使用LINQ-to-SQL时,将Func<>s传递给Where()或Count()是不好的。真正的坏。如果你使用Func<>,那么它调用IEnumerable LINQ的东西,而不是IQueryable,这意味着整个表被拉进来,然后过滤。表达式<Func<>>明显更快,因为它在SQL服务器上执行过滤-特别是如果您正在查询位于另一个服务器上的数据库。
这是我的两分钱…
Func<T> =一个刚被执行的委托/方法,仅此而已。 表达式<Func<T>> =转换为另一种形式。例如,LINQ to Entities表达式被转换为等效的SQL查询。
想象一下,两者看起来很相似,但表达式就像一个数据结构,具有反射的能力。编译器实际上知道关于它的签名和主体的所有信息(类似于类反射)。利用这些知识,表达式被转换为其他形式,就像LINQ被转换为SQL查询一样。
现在,还有另一个角度来处理IQueryable行为。建议您始终传递LINQ的Expression to Where或Count方法,以便您的查询过滤器在SQL server上运行,而不是在内存中提取数据然后进行过滤。