_ => ¿Qué significa este subrayado en las expresiones Lambda?


111

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

8
Hola y bienvenido a StackOverflow. Me tomé la libertad de editar ligeramente su pregunta para aumentar sus posibilidades de obtener respuestas útiles, espero que no le importe.
Lasse V. Karlsen

Tenga en cuenta que, asumiendo que listes un IEnumerable<T>, podrían (y deberían) haber usadosum = list.Count();
BlueRaja - Danny Pflughoeft

Supongo que esto puede usarse para evitar que "contamine" el alcance con un nuevo nombre de variable que podría usarse en otro lugar y causaría un conflicto.
Tim Schmelter

Respuestas:


84

Esa es una convención que se usa cuando no le importa el parámetro.


3
Es más común en Haskell y otros lenguajes funcionales. Creo que de ahí viene.
Gabe Moothart

10
En Haskell, ML, Scala y otros, _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.
Jörg W Mittag

@ JörgWMittag True en mayo de 2010, pero no en junio de 2010. ¡Magnífico momento! :) stackoverflow.com/q/6397078/38765
Andrew Grimm

38

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;

1
En lugar de _, ¿podemos usar ()?
amesh

2
¿Intentaste usar eso?
Lasse V. Karlsen

Sí, lo había usado cuando estaba creando un hilo usando expresión lambda. Thread t= new Thread(()=>doSomething(x,y)); t.start();
amesh

Lo que supongo es que el uso de _ pasa cada variable de la colección a la expresión lambda aunque no se use. Pero cuando usamos () puede que no suceda. Me refiero al parámetro menos lambda.
amesh

Debe probarlo usando la llamada al método ForEach. Hay una sobrecarga en el constructor de Thread que toma un delegado que no toma ningún parámetro. Intente llamar a un método, como ese ForEach, que toma un delegado que toma un parámetro en su lugar.
Lasse V. Karlsen


10

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


7

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.


2
+1 para este enfoque! Pensé que era el único que usaba guiones bajos en lambdas para "reducir el peso cognitivo" y no para mostrar que este parámetro no se usa. Se lee más fácilmente con guiones bajos, especialmente si hay mucho encadenamiento y puede inferir inmediatamente el tipo, como suele ser el caso de las consultas LINQ.
Varvara Kalinina

3
Do(id => Log(id))se abrevia mejor como Do(Log).
Aluan Haddad
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.