Почему круглые скобки вокруг лямбда-оператора вызывают синтаксическую ошибку?
Я ищу хорошее объяснение, почему одна часть кода не компилируется, а другая компилируется просто отлично.
не удается:
richTextBox1.Invoke(new MethodInvoker((() => { richTextBox1.AppendText("test"); })));
выдает ошибку
имя метода ожидаемых
в открывающей скобке сразу после MethodInvoker(
. По-видимому, я не могу заключить свои лямбда-утверждения в скобки.
Compiles:
richTextBox1.Invoke(new MethodInvoker(() => { richTextBox1.AppendText("test"); }));
вопросы - почему?
Я всегда принимал это как должное что я мог бы обернуть любой метод param в скобки, если бы захотел, но, по-видимому, это не так с лямбда-выражениями. Я понимаю, что они несколько особенные, но я все еще не вижу для этого веской причины. Может, я чего-то не понимаю в синтаксисе. Я бы очень хотел его получить.
кстати, это представлено в VS2008, .NET 3.5 SP1, я еще не тестировал его в VS2010 и .NET 4.
3 ответов
Это не лямбда-выражение, это выражение в скобках, которое содержит лямбда-выражение. Таким образом, узел для этого параметра в дереве абстрактного синтаксиса для вызова этого метода будет выражением в скобках, а не лямбда-выражением, как того требует спецификация. Вот почему.
есть и другие места, где компилятор Microsoft C# нарушает спецификацию и принимает такое выражение, даже если оно не должно (согласно спецификации), но это не один из них.
соответствующий раздел спецификации §6.5.
вы ошибаетесь в предположении, что вы написали "метод param". Созданная вами конструкция не является вызовом метода, вы написали создание делегата выражение (см. спецификацию C#, раздел 7.6.10.5), которая должна иметь один аргумент, который должен быть либо
- группа метод,
- анонимная функция или
- значение типа времени компиляции dynamic или A тип делегата.
в вашем случае это не группа методов (сообщение об ошибке намекает, что там ожидается имя метода), ни анонимная функция (поскольку это выражение, которое "где-то внутри" содержит анонимную функцию), ни значение указанных типов.
Если вы написали вызов метода, вы действительно можете обернуть параметр в круглые скобки, даже если он содержит лямбда-выражение:
void Method(Action action)
{
}
...
Method((() => { Console.WriteLine("OK"); }));
потому что компилятор ожидает ()=>{}
внутри 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") );