下面的 Lambda 没有大括号就可以了
是的,但是这是一个表达式 lambda而不是一个声明 lambda。从这些文档中:
语句 lambda 类似于表达式 lambda,只不过语句括在大括号中
这是一个有点奇怪的问题,因为大括号的使用是什么makes它是一个 lambda 语句。回答b绝对是正确的,因为它是唯一的错误断言:statement lambdascan返回值。
语句 lambda 绝对可以包含多个语句,并且绝对可以返回一个值,尽管它必须使用 return 语句来执行此操作:
// Statement lambda with multiple statements, returning a value.
Func<int> statementLambda = () =>
{
int x = 2;
return x * 5;
};
关于术语的一点说明:我更喜欢术语“表达式体 lambda”和“块体 lambda”,部分原因是它更符合规范:
匿名函数体:
表达
block
然而,我们仍坚持使用目前的术语:(
要回答 dee zg 的答案(以及后面的评论)中的观点,请考虑以下两个赋值语句:
Action action = () => { Console.WriteLine("Statement lambda"); };
Action action2 = () => Console.WriteLine("Expression lambda");
第二个 lambda 表达式确实is表达式 lambda。 lambda 的主体是一个表达式而不是一个块。表达方式是这样的:
Console.WriteLine("Expression lambda")
(请注意,它没有分号;分号属于赋值。)
这对于表达式来说很不寻常,因为它没有结果。这是一个调用表达式,这是一种陈述表达式使用规范术语,并且仅在少数情况下允许。不过,在 lambda 表达式的转换中这很好。从第 11.7.1 节ECMA C# 5 标准(“匿名函数转换/一般”):
具体来说,匿名函数 F 与委托类型 D 兼容,前提是:
...
- 如果身体
F
是一个表达式,并且D
has a void
返回类型或F
is async
and D
有返回类型Task
,那么当每个参数F
给出了相应参数的类型D
,F 的主体是一个有效的表达式(w.r.t §12),允许作为陈述表达式(第 13.7 节)。
A 陈述表达式(如第 13.7 节所述)可以是以下任意一种:
- 调用表达式
- 对象创建表达式
- 任务
- 后增量表达式
- 后递减表达式
- 预增量表达式
-
预减表达式
- 等待表达式
在这种情况下,我们有一个调用表达式(调用Console.WriteLine
方法);一个没有结果的人。
请注意,虽然这两个 lambda 表达式在这里看起来几乎相同,但还是有区别:语句 lambda 不能转换为表达式树,而表达式 lambda 可以:
// Invalid: error CS0834: A lambda expression with a statement body
// cannot be converted to an expression tree
Expression<Action> action = () => { Console.WriteLine("Statement lambda"); };
// Valid
Expression<Action> action2 = () => Console.WriteLine("Expression lambda");
要进一步阅读有关表达式分类的内容,请参阅第 12.2.1 节:
表达式被分类为以下之一:
...
- 没有什么。当表达式是对返回类型为 void 的方法的调用时,会发生这种情况。分类为无的表达式仅在语句表达式的上下文中有效(第 13.7 节)。
虽然我们通常将表达式视为计算值,但并非每个表达式都是如此。
有关调用表达式的更多详细信息,我们可以参阅第 12.7.6 节(重点是我的):
计算调用表达式的结果分类如下:
- If the 调用表达式调用返回 void 的方法或委托,结果什么也没有。仅在语句表达式的上下文中才允许被分类为无的表达式 (§13.7)或者作为 lambda 表达式的主体(第 12.16 节)。否则会发生绑定时错误。
- 否则,结果是一个值,具有方法或委托的返回类型的关联类型。 [...]