2011-02-07 5 views
10

Estoy buscando una buena explicación de por qué una pieza de código no se puede compilar y la otra compila muy bien.¿Por qué los paréntesis alrededor de la sentencia lambda causan un error de sintaxis?

falla:

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

da el error

Nombre de método espera

en el paréntesis de apertura justo después MethodInvoker(. Aparentemente, no puedo ajustar mis declaraciones de lambda entre paréntesis.

Compila:

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

La pregunta es - ¿por qué?

Siempre he dado por hecho que podría envolver cualquier parámetro de método entre paréntesis si quisiera pero aparentemente ese no es el caso con las expresiones lambda. Entiendo que son algo especiales, pero todavía no puedo ver una buena razón para esto. Tal vez no entiendo algo sobre la sintaxis. Realmente me gustaría obtenerlo.

Por cierto, esto se presenta en VS2008, .NET 3.5 SP1, aún no lo he probado en VS2010 y .NET 4.

Respuesta

7

No es una expresión lambda, es una expresión entre paréntesis que contiene una expresión lambda Por lo tanto, el nodo para este parámetro en el árbol de sintaxis abstracta para esta invocación de método sería una expresión entre paréntesis, y no una expresión lambda según lo requerido por la especificación. Esta es la razón por.

Hay otros lugares donde el compilador de Microsoft C# infringe la especificación y acepta esa expresión aunque no debería (según la especificación) pero este no es uno de ellos.

La sección correspondiente de la especificación es §6.5.

+0

Gracias, eso tiene sentido. Solo por curiosidad, ¿puedes dar un ejemplo de ese lugar? – Dyppl

+3

@Dyppl: 'Func F() {return (() => 1); } 'es legal, pero según la especificación no debería ser. – jason

+0

gracias! Bueno, entonces me siento un poco mejor con mi pregunta. Tal inconsistencia arruinará tu cabeza eventualmente – Dyppl

3

Porque el compilador espera ()=>{} dentro del método Invoke() y en el primer ejemplo no lo encuentra. Todo lo que está entre paréntesis se evalúa primero devolviendo un solo objeto, en cuyo caso el compilador espera la referencia a un delegado.

Editado He resuelto el mismo problema con este método de extensión:

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

para que pueda llamar

RichTextBox rtb = new RichRextBox(); 
... 

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

En realidad, los delegados anónimos también son azúcar sintáctica; el compilador de C# no está traduciendo la sintaxis lambda a la sintaxis de delegado anónimo. Se traduce tanto en funciones concretas (o clases con funciones, dependiendo de cierres) como en delegados tradicionales. –

4

Se equivoca en la premisa de que ha escrito un "método param". La construcción que ha creado no es una llamada a método, ha escrito una expresión de creación de delegado (consulte la especificación C#, sección 7.6.10.5), que se supone que tiene un solo argumento, el cual deberá ser ya sea

  • un grupo método,
  • una función anónima o
  • un valor de tipo tiempo de compilación dinámica o un tipo de delegado .

En su caso, no es un grupo de métodos (el mensaje de error sugiere que se espera un nombre de método), ni una función anónima (ya que es una expresión que "en el interior" contiene una función anónima), ni un valor de dichos tipos.

Si usted escribió una invocación método, usted podría, de hecho, envuelva el parámetro entre paréntesis, incluso si contiene una expresión lambda:

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