C# Lambda表达式语法:是否需要括号?

16

我是C#的新手,之前看到的Lambda表达式像这样:

(params) => { expression; }

但在 LINQ 中,我看到像这样的例子:

IEnumerable<string> customerFirstNames = customers.Select(cust => cust.FirstName);

没有括号。

(我实际上指的是{}() - 无论我们称它们为大括号、小括号还是中括号)。

它们是相同的,还是有区别吗?

非常感谢。


你是指大括号,中括号还是两者都包括?有很多种解释- http://en.wikipedia.org/wiki/Bracket 是指参数列表、代码体还是两者都包括(整个表达式)? - John K
14
{ } 表示大括号,( ) 表示小括号,[ ] 表示中括号(在编程术语中)。 - Donnie
3
在英国,{}表示花括号,()表示圆括号,[]表示方括号。我从未听过有人在现实生活中称()为括号——这可能是另一种可怕的美式用语 :'(. 编辑补充:刚注意到BIDMAS和PEDMAS之间的不同。 - Callum Rogers
1
{} 是开花括号和闭花括号。因为它们看起来像胡须,当你称呼它们时,这样会更清晰明了。 :) - Joel
1
@Callum 'parentheses' 一词用于指代 (),早在美国存在之前就已经存在了。牛津英语词典甚至提供了美式和英式的变体发音,这对于一个美国俚语来说是不太可能的。 - Joren
显示剩余2条评论
3个回答

31
规则如下:
一个Lambda表达式的形式为:
( modifier type parameter, modifier type parameter ...) => { statements }

我们先考虑左侧。

修饰符可以是ref、out或没有。如果没有ref或out修饰符,则所有类型都可以省略。如果有任何ref或out修饰符,则每个参数声明必须有一个已声明的类型。如果任何参数有一个已声明的类型,则每个参数都必须有一个已声明的类型,因此可以省略类型,前提是:(1) 没有引用或输出,(2) 省略了所有类型。否则,必须提供所有类型。

如果恰好有一个参数,且其类型已被省略,则可以选择省略参数列表周围的括号。

这是有关参数列表的所有规则。右侧的规则是:

如果语句列表由一条具有表达式的单个return语句组成:

x => { return x + 1; }

那么大括号、return关键词和分号可以省略:

x => x + 1

此外,如果语句列表由一个语句表达式组成:

x => { x++; } // Not returning the value of x++; only useful for the side effects
x => { new Y(x); } // weird! executing a ctor only for its side effects! But legal!
x => { M(x); } // note, not returning the value of M(x) even if there is one.

那么省略花括号和分号也是合法的:

x => x++
x => new Y(x)  
x => M(x)

请注意,这些现在对读者可能意味着不同的事情!以前我们明确地丢弃返回值;现在Lambda将被视为返回它们。

请注意,这意味着可以对void返回方法使用此技巧。这是实际合法的:

x => Console.WriteLine(x)

噫,不要这样做。千万别这么做。如果你的意思是

x => { Console.WriteLine(x); } 

那就说那个吧。前面的看起来太像你在试图表达

x => { return Console.WriteLine(x); }

当然,这样做是非法的。


在返回void的方法周围加上大括号是一个好习惯。我甚至可以说,如果调用该方法的主要目的是创建副作用,那么将其放在大括号中,使其看起来更像语句。 - user24359
非常详细的解释。非常感谢。 - LLS
1
这是否意味着您认为编写一个接受Expression<Action>的方法会鼓励不良编码行为?虽然我从未这样做过,但当我写下这个问题时,它突然浮现在我的脑海中。 - ShuggyCoUk
我同意@ShuggyCoUk的观点。例如,可将“令人讨厌”的lambda x => Console.WriteLine(x) 转换为Expression<Action<string>>,而x => { Console.WriteLine(x); }则不能。使用“void”表达式的表达式树的一个例子是在设置模拟时,可以设置返回类型为void的方法,例如myMock.Setup(x => x.Initialize()) - Jeppe Stig Nielsen

17

你所指的括号是哪种?( )还是{ }


( )用于参数列表中,当你有多个参数时是必须的:

(a, b, c) => ...

当只有一个参数时,您可以省略它们:

a => ...

{ } 允许你将一些语句组成块并放在 lambda 表达式的主体中:

(a, b, c) => {
                 Console.WriteLine("Hello World!");
                 Console.WriteLine("a = {0}", a);
                 Console.WriteLine("b = {0}", b);
                 Console.WriteLine("c = {0}", c);
                 return a * b + c;
             }

如果没有它们,lambda表达式的主体就是一个表达式

(a, b, c) => a * b + c

你的例子谈论的是大括号而不是中括号? - John K
谢谢,那解释了很多。 - LLS

5
你只需要在有多个参数的情况下使用括号。 更新(当答案在其他人回答后编辑时,这是SO上的惯例...)
在这种情况下使用括号(圆括号“()”和大括号“{}”)是多余的。这些语句是等效的。像ReSharper这样的Visual Studio插件会指出这样的冗余:

http://www.jetbrains.com/resharper/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接