.NET Разработчик
6.55K subscribers
442 photos
3 videos
14 files
2.12K links
Дневник сертифицированного .NET разработчика. Заметки, советы, новости из мира .NET и C#.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 1339. #ЗаметкиНаПолях
Пустые Переменные в Лямбдах
В твиттере задали интересный вопрос:
Имеет ли смысл использование пустой переменной (дискарда) `_` в выражении типа?
( _ , args) =>{…}
Я ожидаю параметр, но не буду с ним ничего делать.
— Layla #WomenOfDotNet (@LaylaCodesIt)

Короткий ответ: да. Но кому нужны простые ответы? Пустые переменные появились в C# недавно. А это значит, что не всё так просто, как кажется.

В C# есть несколько мест, где мы используем _ как пустую переменную. В примере ниже _ технически не является ей:
Func<int, int, int> f = (_, x) => 2 * x;

Лямбда здесь имеет два параметра, первый называется _, а второй называется x. C# принимает _ в качестве идентификатора в соответствии с правилами языка. Даже Visual Studio при наведении курсора на _ показывает подсказку «(parameter) int _». Мы можем продемонстрировать это, используя оба параметра:
Func<int, int, int> f2 = (_, x) => _ * x;

Следующий код не работал в C#8, но C#9 позволяет так писать:
Func<int, int, int> f3 = (_, _) => 42;

Здесь символы подчеркивания действительно являются пустыми переменными. (Правило состоит в том, что если лямбда имеет несколько параметров с именем _, то все они отбрасываются). A Visual Studio при наведении курсора на _ показывает подсказку «(discard) int _». Однако это работает только для лямбда-выражений.

Зачем это нужно?
Иногда мы вынуждены принимать аргументы, которые не будем использовать. Неиспользуемые параметры выглядят так, как будто это может быть ошибкой:
void ShowNumber(int i)
{
Console.WriteLine(42);
}

Анализатор кода не выдаёт даже предупреждения, а выдаёт только сообщение IDE0060 уровня Message о неиспользуемой переменной. Однако читателю этого кода неочевидно, есть ли ошибка в коде метода или так и задумано. При этом, если вы фанат чистых сборок — без предупреждений и сообщений анализатора, — тогда изменения кода, приводящие к появлению новых сообщений, немедленно привлекут ваше внимание.

Поэтому принято соглашение об использовании _ в качестве имени параметра, который бы намеренно игнорировался. Если вы измените предыдущий пример, переименовав параметр i в _, вы увидите, что компилятор перестанет выдавать сообщение IDE0060, поскольку он знает об этом соглашении:
void ShowNumber(int _)

Но, если у вас есть два параметра, которые вы хотите игнорировать:
void ShowNumber(int _, int _)
это вызовет ошибку компиляции CS0100 из-за дублирующего имени параметра _, т.к. пустые переменные можно использовать только в лямбдах.

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

Всё становится ещё интереснее, когда _ используется в качестве имени локальной переменной. Например, что, по-вашему, выведет код с картинки ниже в C#9+?

Источник: https://endjin.com/blog/2022/09/csharp-lambda-discards
👍5