我理解lambdas和Func和Action委托。但表情 我头疼不已。
在什么情况下,你会使用表达式<Func<T>>而不是普通的旧Func<T>?
我理解lambdas和Func和Action委托。但表情 我头疼不已。
在什么情况下,你会使用表达式<Func<T>>而不是普通的旧Func<T>?
当前回答
LINQ是典型的例子(例如,与数据库对话),但事实上,任何时候您更关心表达要做什么,而不是实际做什么。例如,我在protobuf-net的RPC堆栈中使用这种方法(以避免代码生成等)-所以你调用一个方法:
string result = client.Invoke(svc => svc.SomeMethod(arg1, arg2, ...));
这将分解表达式树以解析SomeMethod(以及每个参数的值),执行RPC调用,更新任何ref/out参数,并从远程调用返回结果。这只能通过表达式树实现。我在这里讲得更多。
另一个例子是为了编译为lambda而手动构建表达式树,就像使用泛型操作符代码一样。
其他回答
主要原因是当您不想直接运行代码,而是想检查它时。这可能有很多原因:
Mapping the code to a different environment (ie. C# code to SQL in Entity Framework) Replacing parts of the code in runtime (dynamic programming or even plain DRY techniques) Code validation (very useful when emulating scripting or when doing analysis) Serialization - expressions can be serialized rather easily and safely, delegates can't Strongly-typed safety on things that aren't inherently strongly-typed, and exploiting compiler checks even though you're doing dynamic calls in runtime (ASP.NET MVC 5 with Razor is a nice example)
在Krzysztof Cwalina的书(框架设计指南:可重用的。net库的约定、习惯用法和模式)中有一个更哲学的解释;
编辑非图像版本:
大多数情况下,如果你只需要运行一些代码,你就需要Func或Action。当代码在运行之前需要分析、序列化或优化时,就需要使用Expression。表达式是用来思考代码的,Func/Action是用来运行代码的。
这是我的两分钱…
Func<T> =一个刚被执行的委托/方法,仅此而已。 表达式<Func<T>> =转换为另一种形式。例如,LINQ to Entities表达式被转换为等效的SQL查询。
想象一下,两者看起来很相似,但表达式就像一个数据结构,具有反射的能力。编译器实际上知道关于它的签名和主体的所有信息(类似于类反射)。利用这些知识,表达式被转换为其他形式,就像LINQ被转换为SQL查询一样。
现在,还有另一个角度来处理IQueryable行为。建议您始终传递LINQ的Expression to Where或Count方法,以便您的查询过滤器在SQL server上运行,而不是在内存中提取数据然后进行过滤。
LINQ是典型的例子(例如,与数据库对话),但事实上,任何时候您更关心表达要做什么,而不是实际做什么。例如,我在protobuf-net的RPC堆栈中使用这种方法(以避免代码生成等)-所以你调用一个方法:
string result = client.Invoke(svc => svc.SomeMethod(arg1, arg2, ...));
这将分解表达式树以解析SomeMethod(以及每个参数的值),执行RPC调用,更新任何ref/out参数,并从远程调用返回结果。这只能通过表达式树实现。我在这里讲得更多。
另一个例子是为了编译为lambda而手动构建表达式树,就像使用泛型操作符代码一样。
当您希望将函数视为数据而不是代码时,可以使用表达式。如果您想操作代码(作为数据),可以这样做。大多数情况下,如果你认为不需要表达式,那么你可能就不需要使用表达式。