_ => co oznacza to podkreślenie w wyrażeniach lambda?

111

Co oznacza wyrażenie lambda _=> expr?

Jaki jest cel _wejścia do lambdy?

Przykład:

int count = 0;
list.ForEach(_ => count += 1);
Prasad
źródło
8
Cześć i witaj w StackOverflow. Pozwoliłem sobie nieco zredagować twoje pytanie, aby zwiększyć twoje szanse na uzyskanie przydatnych odpowiedzi, mam nadzieję, że nie masz nic przeciwko.
Lasse V. Karlsen
Należy pamiętać, że przy założeniu, listto IEnumerable<T>oni mogli (i powinny) być tylko używanesum = list.Count();
BlueRaja - Danny Pflughoeft
Wydaje mi się, że można tego użyć, aby zapobiec „zanieczyszczaniu” zakresu nową nazwą zmiennej, która mogłaby zostać użyta w innym miejscu, co spowodowałoby konflikt.
Tim Schmelter,

Odpowiedzi:

84

To jest konwencja używana, gdy nie zależy Ci na parametrze.

ChaosPandion
źródło
3
Częściej występuje w języku Haskell i innych językach funkcjonalnych. Myślę, że to stąd pochodzi.
Gabe Moothart
10
W Haskell, ML, Scala i innych _jest to znak wieloznaczny w dopasowywaniu wzorców. Zasadniczo oznacza to „Nie obchodzi mnie to, zawsze chcę, żeby to pasowało”. To „nie obchodzi mnie” jest następnie przenoszone, jeśli chodzi o nazywanie rzeczy, na których nie zależy, a stamtąd przenosi się do innych języków programowania. Na przykład jest również używane w języku Ruby w znaczeniu tego samego, co w tym przykładzie, mimo że _nie ma absolutnie żadnego specjalnego znaczenia w języku Ruby.
Jörg W Mittag
@ JörgWMittag Prawda w maju 2010, ale nie w czerwcu 2010. Niesamowite wyczucie czasu! :) stackoverflow.com/q/6397078/38765
Andrew Grimm
38

Jest to nazwa parametru, choć nie jest użyteczna, ale jest zwykle używana (przez niektóre konwencje), gdy musisz określić, że wyrażenie ma parametr, aby kod został skompilowany, ale tak naprawdę cię to nie obchodzi o tym, więc po prostu to zignorujesz.

Zasadniczo wykorzystuje składnię dla tego, co stanowi identyfikator prawny w C #, a ponieważ identyfikator może zaczynać się od podkreślenia i nie zawierać nic więcej, jest to tylko nazwa parametru.

Mogłeś po prostu napisać:

var _ = 10;
Lasse V. Karlsen
źródło
1
Czy zamiast _ możemy użyć ()?
amesh,
2
Czy próbowałeś tego użyć?
Lasse V. Karlsen,
Tak, użyłem go podczas tworzenia wątku przy użyciu wyrażenia lambda. Thread t= new Thread(()=>doSomething(x,y)); t.start();
amesh,
Zakładam, że użycie _ powoduje przekazanie każdej zmiennej kolekcji do wyrażenia lambda, nawet jeśli nie jest ona używana. Ale kiedy używamy (), może się to nie zdarzyć. Mam na myśli parametr mniej lambda.
amesh,
Musisz to wypróbować, używając wywołania metody ForEach. W konstruktorze Thread istnieje przeciążenie, które przyjmuje delegata, który nie przyjmuje żadnych parametrów. Spróbuj wywołać metodę, taką jak ForEach, która przyjmuje delegata, który zamiast tego przyjmuje parametr.
Lasse V. Karlsen,
29

_jest prawidłową nazwą zmiennej. Po prostu używają _jako zmiennej.

BlueRaja - Danny Pflughoeft
źródło
10

Ponieważ wyrażenie lamda jest najczęściej używane w krótkim, anonimowym kodzie, więc nazwa zmiennej czasami nie jest potrzebna, nawet oni nie używają zmiennej w bloku kodu, więc dają tylko _ na krótką konwencję

vodkhang
źródło
7

Popieram również użycie _ => _.method()dla jednowierszowych lambd wywołań metody, ponieważ zmniejsza to wagę poznawczą instrukcji. Szczególnie, gdy używamy typów ogólnych, pisząc x => x.method()po prostu dodajemy do rozważenia ułamek sekundy „Co to jest 'x'? Czy to współrzędna w przestrzeni?”.

Rozważ następujący przypadek:

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

Używany z wywołaniem typu Generics, podkreślenie w tym przypadku działa jak „symbol obejścia”. Unika redundancji, definiując, że typ argumentu jest oczywisty i można go wywnioskować z użycia - tak jak w przypadku użycia „var”, aby zapobiec powtarzaniu deklaracji typu. Pisanie client=>client.Init()tutaj po prostu wydłużyłoby instrukcję bez nadawania jej znaczenia.

Oczywiście nie dotyczy to parametrów, które mają być przekazane do metody, które należy nazwać opisowo. Na przykład.:Do( id=>Log(id) );

Użycie pojedynczego parametru podkreślenia dla wywołań metod jest mało uzasadnione, gdy używa się bloku kodu zamiast jednowierszowego, ponieważ identyfikator lambda zostaje odłączony od jego definicji generycznej. Ogólnie rzecz biorąc, jeśli ten sam identyfikator ma być ponownie użyty, należy nadać mu opisową nazwę.

Najważniejsze jest to, że gadatliwość jest uzasadniona tylko dla ujednoznacznienia, zwłaszcza w przypadku lambd, które zostały stworzone przede wszystkim w celu uproszczenia tworzenia anonimowych delegatów. W każdym razie należy kierować się zdrowym rozsądkiem, równoważąc czytelność i zwięzłość. Jeśli symbol jest tylko „zaczepem” do rzeczywistej funkcjonalności, identyfikatory jednego znaku są w porządku. Tak jest w przypadku pętli For oraz liter „i” i „j” jako indeksatorów.

MaDDoX
źródło
2
+1 za to podejście! Myślałem, że byłem jedynym, który używał podkreślenia w lambdach, aby „zmniejszyć wagę poznawczą”, a nie po to, by pokazać, że ten parametr nie jest używany. Czyta się łatwiej dzięki podkreśleniom, zwłaszcza jeśli jest dużo łańcuchów i możesz od razu wywnioskować typ, jak to często ma miejsce w przypadku zapytań LINQ!
Varvara Kalinina
3
Do(id => Log(id))jest lepiej skracany jako Do(Log).
Aluan Haddad,