我正在寻找一个很好的解释,为什么一段代码无法编译,而另一段代码编译得很好。
失败:
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中测试它。
答案 0 :(得分:7)
它不是lambda表达式,它是包含lambda表达式的带括号的表达式。因此,此方法调用的抽象语法树中此参数的节点将是带括号的表达式,而不是规范要求的lambda表达式。这就是原因。
在其他地方,Microsoft C#编译器确实违反了规范并接受了这样的表达式,即使它不应该(根据规范),但这不是其中之一。
规范的相关部分是§6.5。
答案 1 :(得分:4)
你错误地认为你已经写了一个“方法参数”。你创建的构造不是方法调用,你已经编写了一个委托创建表达式(参见C#规范,第7.6.10.5节),它应该有一个参数,它必须是
在你的情况下,它不是一个方法组(错误消息暗示在那里有一个方法名称),也不是一个匿名函数(因为它是一个“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") );