_ => que signifie ce trait de soulignement dans les expressions Lambda?

111

Que signifie une expression lambda comme _=> expr?

À quoi sert une _entrée dans lambda?

Exemple:

int count = 0;
list.ForEach(_ => count += 1);
Prasad
la source
8
Bonjour et bienvenue sur StackOverflow. J'ai pris la liberté de modifier légèrement votre question pour augmenter vos chances d'obtenir des réponses utiles, j'espère que cela ne vous dérange pas.
Lasse V. Karlsen
Notez que, en supposant que listc'est un IEnumerable<T>, ils pourraient (et devraient) avoir juste utilisésum = list.Count();
BlueRaja - Danny Pflughoeft
Je suppose que cela peut être utilisé pour éviter que vous «polluiez» la portée avec un nouveau nom de variable qui pourrait être utilisé ailleurs, ce qui provoquerait un conflit.
Tim Schmelter

Réponses:

84

C'est une convention utilisée lorsque vous ne vous souciez pas du paramètre.

ChaosPandion
la source
3
C'est plus courant dans Haskell et d'autres langages fonctionnels. Je pense que c'est de là que ça vient.
Gabe Moothart
10
Dans Haskell, ML, Scala et autres, _est le caractère générique dans la correspondance de modèle. Cela signifie essentiellement "Je m'en fiche, je veux toujours que ça corresponde". Ce «je m'en fous» est alors reporté lorsqu'il s'agit de nommer des choses qui ne vous intéressent pas et à partir de là, il déborde dans d'autres langages de programmation. Il est, par exemple, également utilisé dans Ruby pour signifier la même chose que dans cet exemple, même s'il _n'a absolument aucune signification particulière dans Ruby.
Jörg W Mittag
@ JörgWMittag True en mai 2010, mais pas en juin 2010. Un timing formidable! :) stackoverflow.com/q/6397078/38765
Andrew Grimm
38

C'est un nom de paramètre, bien que pas utile, mais c'est celui généralement utilisé (par certaines conventions) lorsque vous devez spécifier que l'expression a un paramètre afin d'obtenir le code à compiler, mais vous ne vous en souciez pas vraiment à ce sujet, alors vous allez simplement l'ignorer.

Il s'agit essentiellement d'exploiter la syntaxe de ce que constitue un identifiant légal en C #, et comme un identifiant peut commencer par un trait de soulignement et ne contenir rien d'autre, c'est juste un nom de paramètre.

Vous auriez pu facilement écrire:

var _ = 10;
Lasse V. Karlsen
la source
1
Au lieu de _, pouvons-nous utiliser ()?
amesh
2
Avez-vous essayé de l'utiliser?
Lasse V. Karlsen
Oui, je l'avais utilisé lorsque je créais un thread en utilisant une expression lambda. Thread t= new Thread(()=>doSomething(x,y)); t.start();
amesh
Ce que je suppose, c'est que l'utilisation de _ passe chaque variable de la collection à l'expression lambda même si elle n'est pas utilisée. Mais lorsque nous utilisons (), cela peut ne pas arriver. Je veux dire le paramètre moins lambda.
amesh
Vous devez l'essayer en utilisant l'appel de méthode ForEach. Il y a une surcharge sur le constructeur Thread qui prend un délégué qui ne prend aucun paramètre. Essayez d'appeler une méthode, comme celle de ForEach, qui prend un délégué qui prend un paramètre à la place.
Lasse V. Karlsen
29

_est un nom de variable valide. Ils utilisent juste _comme variable.

BlueRaja - Danny Pflughoeft
la source
10

Parce que l'expression lamda est principalement utilisée dans un code court et anonyme de sorte que le nom de la variable n'est parfois pas nécessaire, même ils n'utilisent pas la variable dans le bloc de code, de sorte qu'ils donnent juste un _ pour une courte convention

vodkhang
la source
7

J'appuie également l'utilisation de _ => _.method()pour les lambdas d'appels de méthode à une ligne, car cela réduit le poids cognitif de l'instruction. Surtout lors de l'utilisation de génériques, l'écriture x => x.method()ajoute simplement cette considération en une fraction de seconde de "Qu'est-ce que c'est 'x'? Est-ce une coordonnée dans l'espace?".

Prenons le cas suivant:

Initialize<Client> ( _=>_.Init() );

Utilisé avec un appel Generics, le trait de soulignement dans ce cas fonctionne comme un "symbole de contournement". Cela évite la redondance, en définissant que le type de l'argument est évident et peut être déduit de l'utilisation - tout comme lorsque vous utilisez «var» pour éviter de répéter une déclaration de type. Ecrire client=>client.Init()ici ne ferait qu'allonger l'instruction sans lui ajouter de sens.

Évidemment, cela ne s'applique pas aux paramètres à passer à la méthode, qui doivent être nommés de manière descriptive. Par exemple.:Do( id=>Log(id) );

L'utilisation d'un seul paramètre de soulignement pour les appels de méthode est difficilement justifiable lors de l'utilisation d'un bloc de code au lieu d'un one-liner, car l'identificateur lambda est déconnecté de sa définition générique. En général, lorsque le même identifiant doit être réutilisé, donnez-lui un nom descriptif.

L'essentiel est que la verbosité n'est justifiable que pour la désambiguïsation, en particulier pour les lambdas, qui ont été créés pour simplifier la création de délégués anonymes en premier lieu. Dans tous les cas, le bon sens doit être utilisé, en équilibrant la lisibilité et la concision. Si le symbole n'est qu'un "crochet" à la fonctionnalité réelle, les identificateurs à un caractère conviennent parfaitement. C'est le cas des boucles For et des lettres «i» et «j» comme indexeurs.

MaDDoX
la source
2
+1 pour cette approche! Je pensais être le seul à utiliser des traits de soulignement dans les lambdas pour "réduire le poids cognitif" et non pour montrer que ce paramètre n'est pas utilisé. Il est plus facile de lire avec des traits de soulignement, surtout s'il y a beaucoup de chaînage et que vous pouvez immédiatement déduire le type, comme c'est souvent le cas avec les requêtes LINQ!
Varvara Kalinina
3
Do(id => Log(id))est mieux abrégé en Do(Log).
Aluan Haddad