Почему круглые скобки вокруг лямбда-оператора вызывают синтаксическую ошибку?

Я ищу хорошее объяснение, почему одна часть кода не компилируется, а другая компилируется просто отлично.

не удается:

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") );