2009-02-03 77 views
24

我很好奇为什么C#允许我在某些情况下忽略委托参数,而不是其他情况。我可以使用lambda语法忽略委托参数吗?

例如,这是允许的:

Action<int> action = delegate { Console.WriteLine("delegate"); }; 

但这不是:

Action<int> action =() => Console.WriteLine("lambda"); 

有没有一种方法来初始化一个委托,并使用Lambda忽略的参数?我知道我可以给lambda添加一个参数并修复上一行,但这更多的是与编译器有关的学术问题,以及它为什么或如何工作。

回答

17

我相信你的第一个示例实际上创建了一个匿名函数,它能够接受许多不同的签名,其身体是单个语句Console.WriteLine...。因为它可以匹配不同的签名,所以不会导致问题。在第二个示例中,lambda语法本身定义了一个不带相同主体的参数的函数。显然,后者与定义的Action不一致,所以你会得到错误。

C# Anonymous Method Reference

有一种情况,其中一个 匿名方法提供在lambda 表达式没有发现 功能。匿名方法使您可以省略参数列表 ,并且 这意味着可以将具有 各种签名的匿名方法 转换为委托。对于lambda表达式,这不是 。

+1

这是否是正确与否取决于你如何看答案。生成的IL是*绝对*仅用于采用int的方法。编译器*知道它试图将其转换为的编译时类型 - 如果将操作签名更改为“委托”,则会发生编译时错误。 – 2009-07-04 05:59:16

+0

我的意思是(我想我说的)是通过在第一个示例中省略委托的参数列表,编译器在创建方法时填入它,以便它匹配所需的签名。 Lambda表达式不允许您省略参数列表 - 一个空列表推断不带参数的方法 - 因此会导致编译时错误。 – tvanfosson 2009-07-04 14:43:21

2

The()=> ...语法显式指定lambda不带参数。也许语言可以被修改,使得()=>真的意味着“为我推出这个lambda的参数”,就像委托语法一样,但是这会使语言更加复杂。在设计新的语言功能时,you start at minus 100,我不认为这个通过了测试。

可能还有更多的技术原因,为什么这将很难实现(这可能更符合你的要求,但我怀疑技术上的原因推动这个决定,如果它出现了)。

0

我想说它是强制使用lambda表达式的参数。

拿你的第一个例子,你将如何与传入的值进行交互,没有它的本地表示。

8

详细说明tvanfosson的答案;

λ-表达式和 匿名方法表达式的行为是 除了以下几点相同:

•匿名这种行为是在C#3.0语言规范(§7.14)中描述 - 方法表达式允许 参数列表被完全省略 ,产生可兑换为 委托类型的任何值列表 参数。

•拉姆达表达式允许参数 类型可以省略和推断 而 需要的参数类型是 明确说明匿名方法表达式。

•一个lambda表达式的主体可以 是一个表达式或语句块 而一个 匿名方法表达式的主体必须是 语句块。

•由于仅λ-表达式可以 具有表达体,没有 匿名方法表达可以是 成功地转换为一个 表达式树类型(§4.6)。

我想:

Action<int> action =() => Console.WriteLine("lambda"); 

是等价的:

Action<int> action = delegate() { Console.WriteLine("delegate"); }; 

这会也不编译。正如Daniel Plaisted所说()明确表示没有任何参数。

如果有委托的等效{}可能是:

Action<int> action = => Console.WriteLine("lambda") 

这是不是很漂亮,我怀疑这怀疑是不是在lambda表达式的精神。

5

正如别人所说,不,你不能跳过声明参数为lambda。但是,为了清洁,我建议给他们一个像_这样的名字。例如

foo.Click += (_,__) => { ... } 

你并不是无视它们,但你表示你不在乎它们是什么,也不会使用它们。

0

这是怎么回事?

Func<int> lamdapointer =() => TwoArgMethodThatReturnsInt(10,20); // the same method cannot be called with the delegate "NoArgmethodThatReturnsInt" 


lamdapointer(); 

Delegate int NoArgmethodThatReturnsInt(); 
NoArgmethodThatReturnsInt del = NoArgmethodThatReturnsInt; // only this is possible with delegates 


public int TwoArgMethodThatReturnsInt(int x,int y) 
{ 
return x + y; 
} 

public int NoArgmethodThatReturnsInt() 
{ 
return 20; 
} 
0

实际上,委托{}没有指定任何参数并且适合任何委托方法签名 - 因此它在您的第一个构造中是允许的。 Lambda表达式()=> ...;特别声明无参数委托,这与Action所要求的签名相抵触 - 具有单一参数的委托。

您可能想要使用以下选项之一。

如果您需要动作来获取参数,您可以采用下一种方式(“_”是标识符名称的合法字符)。

Action<int> action = _ => Console.WriteLine("lambda");

或者你可能需要使用参数的操作如下:

Action action =() => Console.WriteLine("lambda");

相关问题