2012-10-13 78 views
13

En este fragmento de código:¿Por qué las lambdas pueden convertir llamadas a funciones en Acciones?

List<String> names = new List<String>(); 
names.Add("Bruce"); 
names.Add("Tom"); 
names.Add("Tim"); 
names.Add("Richard"); 

names.ForEach(x => Print(x)); 

private static string Print(string s) 
{ 
    Console.WriteLine(s); 
    return s; 
} 

Print no es una Action seguro ya que está regresando string; sin embargo, x=> Print(x) es, ¿por qué?

+3

Por favor, mejore el título de esta pregunta. Google lo usa para titular sus resultados de búsqueda, y su título no es Googleible en absoluto. –

Respuesta

16

El tipo de la expresión lambda x => Print(x) se determina en función de su contexto. Como el compilador sabe que la lambda está asignada a Action<string>, el compilador ignora el tipo de devolución del método Print(s) como si fuera una expresión de declaración .

Esta es una conversión válida:

Action<string> myAction = y => Print(y); 

En otras palabras, tanto

Print("something"); 

y

int x = Print("something"); 

son usos correcto del método Print; se pueden usar en lambdas de la misma manera.

+0

Dado que Print devuelve cadena, ¿por qué el compilador puede tomar el tipo de devolución como vacío y hacer coincidir Acción? –

+4

Porque algo legal que hacer con la cuerda es tirarlo. No es necesario que especifiques específicamente que estás arrojando un valor de retorno; no usarlo es suficiente. –

+0

De hecho, casi cada vez que asigna una variable, está haciendo lo mismo, ¡ya que las expresiones de asignación devuelven el valor asignado! Entonces una acción que asigna un raible está haciendo lo mismo. –

9

x => Print(x) es un lambda que se convierte en un método que aquí equivale a:

void MyPrintLambda(string x) { Print(x); } 

Si el contexto había llamado para, por ejemplo, un Func<string, string>, que habría sido la siguiente:

string MyPrintLambda(string x) { return Print(x); } 

o si se trataba de un Func<string, object>, que habría sido la siguiente:

object MyPrintLambda(string x) { return Print(x); } 

Porque el compilador puede convertir x => Print(x) en Action<string> simplemente ignorando el tipo de devolución (es decir el primer ejemplo), puede compilar.

+1

El último bit no es del todo correcto, 'names.ForEach (Print)' no se compilará, ya que 'Print' NO se puede convertir en' Acción ',' x => Print (x) 'es, sin embargo, ya que los tipos de expresiones se definen en función del uso – mlorbetske

+0

@mlorbetske, tienes razón, he eliminado ese bit ahora. –

4

Por la misma razón por la que esto sería válida:

foreach (string name in names) 
{ 
    Print(name); 
} 

El método de impresión() devuelve un valor en ese código también, pero nadie esperaría que esto es un error. Se permite simplemente tirar el valor de retorno.

Cuestiones relacionadas