_ => что означает это подчеркивание в лямбда-выражениях?

111

Что означает лямбда-выражение _=> expr?

Какова цель использования _лямбды?

Пример:

int count = 0;
list.ForEach(_ => count += 1);
Прасад
источник
8
Привет и добро пожаловать в StackOverflow. Я позволил себе немного отредактировать ваш вопрос, чтобы увеличить ваши шансы на получение полезных ответов, надеюсь, вы не против.
Лассе В. Карлсен
Следует отметить , что, предполагая listэто IEnumerable<T>, они могут (и должны) только что использовалиsum = list.Count();
BlueRaja - Дэнни Pflughoeft
Я предполагаю, что это можно использовать для предотвращения «засорения» области видимости новым именем переменной, которое может быть использовано где-то еще, что может вызвать конфликт.
Тим Шмелтер

Ответы:

84

Это соглашение используется, когда вам не нужен параметр.

ХаосПандион
источник
3
Это чаще встречается в Haskell и других функциональных языках. Я думаю, что это откуда.
Гейб Мутхарт
10
В Haskell, ML, Scala и других _это подстановочный знак при сопоставлении с образцом. Это в основном означает: «Мне все равно, я всегда хочу, чтобы это совпадало». Это «мне все равно» затем переносится, когда дело доходит до наименования вещей, которые вам не нужны, и оттуда оно перетекает на другие языки программирования. Он, например, также используется в Ruby для обозначения того же значения, что и в этом примере, хотя _в Ruby не имеет абсолютно никакого особого значения.
Jörg W Mittag
@ JörgWMittag Верно в мае 2010 г., но не по состоянию на июнь 2010 г. Отличное время! :) stackoverflow.com/q/6397078/38765
Эндрю Гримм,
38

Это имя параметра, хотя и бесполезное, но оно обычно используется (по некоторым соглашениям), когда вам нужно указать, что выражение имеет параметр, чтобы код компилировался, но вам все равно об этом, так что вы просто проигнорируете это.

Он в основном использует синтаксис того, что представляет собой законный идентификатор в C #, и поскольку идентификатор может начинаться с подчеркивания и не содержать ничего другого, это просто имя параметра.

Вы могли бы легко написать:

var _ = 10;
Лассе В. Карлсен
источник
1
Можем ли мы использовать () вместо _?
amesh 03
2
Вы пробовали это использовать?
Лассе В. Карлсен
Да, я использовал его, когда создавал поток с использованием лямбда-выражения. Thread t= new Thread(()=>doSomething(x,y)); t.start();
amesh 03
Я предполагаю, что использование _ передает каждую переменную коллекции в лямбда-выражение, даже если оно не используется. Но когда мы используем (), этого может и не произойти. Я имею в виду параметр меньше лямбды.
amesh 03
Вам нужно попробовать это с помощью вызова метода ForEach. В конструкторе Thread есть перегрузка, которая принимает делегат, не принимающий никаких параметров. Попробуйте вызвать такой метод, как этот ForEach, который вместо этого принимает делегат, который принимает параметр.
Лассе В. Карлсен
29

_- допустимое имя переменной. Они просто используются _как переменные.

BlueRaja - Дэнни Пфлугхофт
источник
10

Поскольку выражение lamda в основном используется в коротком анонимном коде, поэтому имя переменной иногда не требуется, даже если они не используют переменную в блоке кода, поэтому они просто дают _ для краткого соглашения

водкханг
источник
7

Я также поддерживаю использование _ => _.method()однострочных лямбда-выражений с вызовом метода, поскольку это снижает когнитивный вес инструкции. Особенно при использовании обобщений письмо x => x.method()просто добавляет долю секунды к вопросу «Что это за« x »? Это координата в пространстве?».

Рассмотрим следующий случай:

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

Используемый с вызовом Generics, подчеркивание в этом случае работает как «символ обхода». Он избегает избыточности, определяя, что тип аргумента очевиден и может быть получен из использования - точно так же, как когда вы используете 'var' для предотвращения повторения объявления типа. Написание client=>client.Init()здесь просто сделало бы инструкцию длиннее, не добавляя к ней никакого смысла.

Очевидно, это не относится к параметрам, передаваемым в метод, который следует назвать описательно. Например.:Do( id=>Log(id) );

Использование одного параметра подчеркивания для вызовов методов вряд ли оправдано при использовании блока кода вместо однострочного, поскольку лямбда-идентификатор отключается от определения своего универсального типа. Обычно, когда один и тот же идентификатор должен использоваться повторно, дайте ему описательное имя.

Суть в том, что многословие оправдано только для устранения неоднозначности, особенно для лямбда-выражений, которые были созданы, в первую очередь, для упрощения создания анонимных делегатов. В любом случае следует руководствоваться здравым смыслом, сбалансировав разборчивость и лаконичность. Если символ является лишь «приманкой» к реальной функциональности, односимвольные идентификаторы вполне подойдут. Так обстоит дело с циклами For и буквами «i» и «j» в качестве индексаторов.

MaDDoX
источник
2
+1 за такой подход! Я был единственным, кто использовал символы подчеркивания в лямбдах, чтобы «снизить когнитивный вес», а не для того, чтобы показать, что этот параметр не используется. С подчеркиванием легче читать, особенно если много цепочек и вы можете сразу определить тип, как это часто бывает с запросами LINQ!
Варвара Калинина
3
Do(id => Log(id))лучше сокращать как Do(Log).
Алуан Хаддад