为什么围绕lambda语句的括号会导致语法错误?

时间:2011-02-07 19:35:21

标签: c# visual-studio-2008 c#-3.0 lambda syntax-error

我正在寻找一个很好的解释,为什么一段代码无法编译,而另一段代码编译得很好。

失败:

richTextBox1.Invoke(new MethodInvoker((() => { richTextBox1.AppendText("test"); })));

给出错误

  

预期的方法名称

MethodInvoker(之后的左括号上。显然,我不能用括号括起我的lambda语句。

编译:

richTextBox1.Invoke(new MethodInvoker(() => { richTextBox1.AppendText("test"); }));

问题是 - 为什么?

我总是理所当然地认为,如果我愿意,我可以在括号中包装任何方法参数,但显然不是lambda表达式的情况。我知道它们有点特别,但我仍然看不出有充分的理由。也许我对语法一无所知。我真的很想得到它。

顺便说一句,这在VS2008,.NET 3.5 SP1中提出,我还没有在VS2010和.NET 4中测试它。

3 个答案:

答案 0 :(得分:7)

它不是lambda表达式,它是包含lambda表达式的带括号的表达式。因此,此方法调用的抽象语法树中此参数的节点将是带括号的表达式,而不是规范要求的lambda表达式。这就是原因。

在其他地方,Microsoft C#编译器确实违反了规范并接受了这样的表达式,即使它不应该(根据规范),但这不是其中之一。

规范的相关部分是§6.5。

答案 1 :(得分:4)

你错误地认为你已经写了一个“方法参数”。你创建的构造不是方法调用,你已经编写了一个委托创建表达式(参见C#规范,第7.6.10.5节),它应该有一个参数,它必须是

  • 方法组,
  • 匿名函数或
  • 编译时类型dynamic或delegate-type的值。

在你的情况下,它不是一个方法组(错误消息暗示在那里有一个方法名称),也不是一个匿名函数(因为它是一个“somewhere inside”包含一个匿名函数的表达式),也不是所述类型的值。

如果你编写了一个方法调用,你可以将参数包装在括号中,即使它包含一个lambda表达式:

void Method(Action action)
{
}
...
Method((() => { Console.WriteLine("OK"); }));

答案 2 :(得分:3)

因为编译器期望()=>{}方法中的Invoke(),并且在第一个示例中它找不到它。首先评估括号内的所有内容,返回单个对象,在这种情况下,编译器需要对委托的引用。

<强>被修改 我用这个扩展方法解决了同样的问题:

    public delegate void EmptyHandler();
    public static void SafeCall(this Control control, EmptyHandler method) 
    {
        if (control.InvokeRequired)
        {
            control.Invoke(method);
        }
        else
        {
            method();
        }
    } 

所以你可以打电话给

RichTextBox rtb = new RichRextBox();
...

rtb.SafeCall( ()=> rtb.AppendText("test") );