¿Qué significa una expresión lambda como _=> expr
?
¿Cuál es el propósito de _
como entrada a lambda?
Ejemplo:
int count = 0;
list.ForEach(_ => count += 1);
Esa es una convención que se usa cuando no le importa el parámetro.
_
es el carácter comodín en la coincidencia de patrones. Básicamente significa "No me importa, siempre quiero que esto coincida". Este "no me importa" se transfiere cuando se trata de nombrar cosas que no te importan y, desde allí, se extiende a otros lenguajes de programación. Por ejemplo, también se usa en Ruby para significar lo mismo que en este ejemplo, aunque no _
tiene absolutamente ningún significado especial en Ruby.
Es un nombre de parámetro, aunque no es útil, pero es el que se usa normalmente (según algunas convenciones) cuando necesita especificar que la expresión tiene un parámetro para que el código se compile, pero realmente no le importa al respecto, así que simplemente lo ignorará.
Básicamente, está explotando la sintaxis de lo que constituye un identificador legal en C #, y dado que un identificador puede comenzar con un guión bajo y no contener nada más, es solo un nombre de parámetro.
Podrías haber escrito fácilmente:
var _ = 10;
Thread t= new Thread(()=>doSomething(x,y)); t.start();
_
es un nombre de variable válido. Solo lo están usando _
como una variable.
Debido a que la expresión lamda se usa principalmente en un código corto y anónimo, por lo que el nombre de la variable a veces no es necesario, incluso ellos no usan la variable en el bloque de código, por lo que solo dan un _ para una convención breve
También secundo el uso de _ => _.method()
lambdas de llamada de método de una línea, ya que reduce el peso cognitivo de la instrucción. Especialmente cuando se usan genéricos, la escritura x => x.method()
solo agrega esa consideración de fracción de segundo de "¿Qué es esta 'x'? ¿Es una coordenada en el espacio?".
Considere el siguiente caso:
Initialize<Client> ( _=>_.Init() );
Usado con una llamada Generics, el guión bajo en este caso funciona como un "símbolo de bypass". Evita la redundancia, definiendo que el tipo de argumento es obvio y se puede inferir del uso, al igual que cuando usa 'var' para evitar que se repita una declaración de tipo. Escribir client=>client.Init()
aquí solo alargaría la instrucción sin agregarle ningún significado.
Obviamente, esto no se aplica a los parámetros que se pasarán al método, que debe nombrarse de forma descriptiva. P.ej.:Do( id=>Log(id) );
El uso del parámetro de subrayado único para las llamadas a métodos es difícilmente justificable cuando se usa un bloque de código en lugar de una sola línea, ya que el identificador lambda se desconecta de su definición genérica. En general, cuando se va a reutilizar el mismo identificador, asígnele un nombre descriptivo.
La conclusión es que la verbosidad solo se justifica para la desambiguación, especialmente para las lambdas, que se crearon para simplificar la creación de delegados anónimos en primer lugar. En cualquier caso, conviene utilizar el sentido común, equilibrando la legibilidad y la concisión. Si el símbolo es sólo un "gancho" a la funcionalidad real, los identificadores de un carácter están perfectamente bien. Ese es el caso de los bucles For y las letras "i" y "j" como indexadores.
Do(id => Log(id))
se abrevia mejor como Do(Log)
.
list
es unIEnumerable<T>
, podrían (y deberían) haber usadosum = list.Count();