Заметка о discards в C# - это скорре краткий пересказ документации с небольшими добавлениями.
Discards или "отмена" - это механизм, позволяющий пометить некоторое значение в коде как не используемое (placeholder).
Discards - это как переменная которой не присвоено значение и при попытке использовать такую переменную мы получим CS0103, "The name '_' doesn't exist in the current context".
You may want to ignore the result of an expression, one or more members of a tuple expression, an out parameter to a method, or the target of a pattern matching expression.
То есть, предполагается что мы можем это использова для игнорирования
static (double, double, double) GetXYZ() {
return (1.0, 2.0, 3.0);
}
var (_, _, Z) = GetXYZ();
В этом примере мы пропускаем значения для X, Y и хотим дальше использовать только значение для Z и определяем переменную с именем "Z" для него.
int Value = 2;
string Message = Value switch
{
1 => "Value == 1",
2 => "Value == 2",
_ => "Value >= 3"
};
это пример, показывающий, как можно использовать discards для определения "default" бранч в switch.
Также, мы можем использовать тип
string Message = Value switch
{
AppEntity1 _ => "AppEntity1 type",
AppEntity2 _ => "AppEntity2 type",
_ => "other type"
};
Можно "скипнуть" out параметры метода
Например
DateTime.TryParse("2022-05-01T14:57:32.8375298-04:00", out _)
Пример из документации. Очень лаконичный способ проверки переменной на null.
_ = arg ?? throw new ArgumentNullException(paramName: nameof(arg), message: "arg can't be null");
здесь используется discard чтобы игнорировать результат выполнения выражения.
Пример из документации.
_ = Task.Run(() =>
...
если явно не обозначить что мы игнорируем объект Task, то компилятор выдаст предупреждение.
Мы можем игнорировать пареметры лямбда выражений используя discard заполнители
(_, _) => { /* to do something*/ };
// or
(int _, string _) => { /* to do something*/ };
Имя "_" - это валидное имя переменной, поэтому если оно использована не в контексте discard мы получим настоящую переменную с таким именем. Например
private static void ToDoSomething(string _)
{
...
}
мы сможем использовать такой вариант и работать с парметром "_" внутри метода ToDoSomething
.
NOTE Не стоит так делать, так как это, с высокой вероятностью, приведет вас к ошибкам. Подробнее про ошибки - в документации.
Нет. Не завезли.
Мы, конечно, можем написать так
var list = Stream.of(1, 2, 3)
.filter(unusedParameter -> true)
.collect(Collectors.toList());
Но такое решение - это не discard
Возможно, эту фичу когда-нибудь имплементируют и в Java.
На момент openjdk-18.0.1.1, это выглядит так:
var list = Stream.of(1, 2, 3)
.filter((Integer _) -> true)
.collect(Collectors.toList());
// compile error: As of Java 9, '_' is a keyword, and may not be used as an identifier
var list = Stream.of(1, 2, 3)
.filter(_ -> true)
.collect(Collectors.toList());
// compile error: As of Java 9, '_' is a keyword, and may not be used as an identifier
В примере ниже - работает. Но это обычная переменная/параметр :)
var list3 = Stream.of(1, 2, 3)
.filter(__ -> __ > 3)
.collect(Collectors.toList());