2010-04-22 13 views
24

Espero haber redactado el título de mi pregunta de manera apropiada.¿Por qué no puedo usar # lambdas o delegados anónimos en línea?

en C# que puedo utilizar lambdas (como delegados), o la sintaxis delegado más para hacer esto:

Func<string> fnHello =() => "hello"; 
Console.WriteLine(fnHello()); 

Func<string> fnHello2 = delegate() 
{ 
    return "hello 2"; 
}; 
Console.WriteLine(fnHello2()); 

¿Por qué no puedo "en línea" de la lambda o el cuerpo de delegados, y evitar la captura en una variable con nombre (por lo que es anónimo)?

// Inline anonymous lambda not allowed 
Console.WriteLine(
    (() => "hello inline lambda")() 
); 

// Inline anonymous delegate not allowed 
Console.WriteLine(
    (delegate() { return "hello inline delegate"; })() 
); 

Un ejemplo que funciona en javascript (sólo para comparación) es:

alert(
    (function(){ return "hello inline anonymous function from javascript"; })() 
); 

que produce el cuadro de alerta esperado.

ACTUALIZACIÓN: Parece que puede tiene una lambda en el anonimato en línea en C#, si lanzas apropiadamente, pero la cantidad de arranques ('s) para que sea ingobernable.

// Inline anonymous lambda with appropriate cast IS allowed 
Console.WriteLine(
    ((Func<string>)(() => "hello inline anonymous lambda"))() 
); 

Tal vez el compilador no puede inferir la firma del delegado anónimo para saber qué Console.WriteLine() que está tratando de llamar? ¿Alguien sabe por qué se requiere este elenco específico?

+0

Considere esto: 'public static R Eval (Func m) {return m();}'. A continuación, puede decir 'Eval (() => {return" test ";})' que es un poco más agradable, o incluso 'Eval (() => {return" test ";})'. – Ben

Respuesta

19

Lambdas en C# no tienen tipos, hasta que se utilizan en un contexto que los transfiere a un tipo de delegado o Expresión. Es por eso que no se puede decir

var x =() => "some lambda"; 

Es posible disfrutar de

http://blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous-methods-part-two.aspx

http://blogs.msdn.com/ericlippert/archive/2007/01/12/lambda-expressions-vs-anonymous-methods-part-three.aspx

+0

+1. Concepto básico importante con respecto a lambdas en C#. – Cheeso

2

Puede usar expresiones lambda en línea para los métodos que toman en un parámetro de Delegado.

Sin embargo, hay un pequeño inconveniente: si el parámetro se escribe como el tipo de Delegado base, deberá convertirlo explícitamente en una derivación específica de Delegado (por ejemplo, Acción); de lo contrario, el compilador se quejaría.

preguntas similares:
Anonymous method in Invoke call
Anonymous methods and delegates

8

Cuando se escribe Func<string> = ..., el compilador sabe que tiene que crear un objeto de tipo Func<string>. Pero cuando escribe ese delegado en línea, el compilador no conoce el objeto del tipo que debe crear.

Habiendo dicho lo anterior, se puede sacar una conclusión obvia: simplemente dígale al compilador el tipo explícitamente.

Console.WriteLine(new Func<string>(() => "Hello")()); 

ACTUALIZACIÓN

Ok, mientras estaba escribiendo la respuesta, que actualizó su puesto. Creo que mi respuesta anterior ya responde a la pregunta "por qué se requiere este tipo específico". Para reiterar: porque el compilador no conoce el objeto de qué tipo crear.

ahora a elaborar un poco sobre la "el compilador no puede inferir la firma del delegado anónimo" parte. Ya ves, no es como en JavaScript. En C#, no hay un tipo genérico de "función" (o "método"). Cada delegado debe tener una firma y un nombre de tipo explícitamente especificados. Y cuando está creando un delegado, el compilador debe saber qué tipo.

Ahora, puedo ver cómo puede implicar que el compilador podría simplemente construir un tipo de delegado sobre la marcha, como lo hace con los tipos de objetos anónimos (también conocido como new { a = 1, b = "xyz" }). Pero piénselo un momento: probablemente no habría ningún uso para tal delegado de todos modos. Quiero decir, no puedes pasarlo a otro método, porque ese método primero tiene que declarar los tipos de sus argumentos. Y puede crear un evento, porque, nuevamente, debe tener un tipo con nombre.

Algo así ...

11

Parece que funciona si le dan un tipo de reparto:

String s = ((Func<String>) (() => "hello inline lambda"))(); 

¿Es inútil? No completamente. Tome el siguiente:

String s; 
{ 
    Object o = MightBeNull(); 
    s = o == null ? "Default value" : o.ToString(); 
} 

ahora esto:

String S = ((Func<Object,String>)(o => o == null ? "Default value" : o.ToString()) 
    )(MightBeNull()); 

Es un poco feo, pero es compacto.

Cuestiones relacionadas