Я читал о новых функциях переменных в C # 7 здесь . У меня два вопроса:
Это говорит
Мы также разрешаем "отбрасывать" как параметры out в форме a
_
, чтобы вы могли игнорировать параметры, которые вам не нужны:p.GetCoordinates(out var x, out _); // I only care about x
В: Думаю, это всего лишь информация, а не новая функция C # 7, потому что мы можем сделать это и в версии до C # 7.0:
var _; if (Int.TryParse(str, out _)) ...
или мне что-то здесь не хватает?
Мой код выдает ошибку, когда я делаю, как указано в том же блоге:
~Person() => names.TryRemove(id, out *);
*
не является допустимым идентификатором. Я полагаю, это недосмотр Мадса Торгерсена?
out _
_
не является переменной, вы не объявляете ее и не можете использовать по имени. Вint _
том , что это переменная.out _
безvar
. Сvar
ним это действительно так же , как и раньше.Console.WriteLine(_)
- это не будет компилироваться, утверждая, что такой переменной нет. Довольно странно. Более того: если вы сделаете что-то подобное_ = SomeMethodCall()
- это будет заменено простоSomeMethodCall()
в скомпилированном коде. В конце концов, вы по-прежнему не можете использовать эту переменную в каком-либо значимом смысле.Ответы:
Discards в C # 7 может использоваться везде, где объявлена переменная, чтобы - как следует из названия - отбросить результат. Таким образом, сброс можно использовать без переменных:
p.GetCoordinates(out var x, out _);
и его можно использовать для отбрасывания результата выражения:
_ = 42;
В этом примере
p.GetCoordinates(out var x, out _); _ = 42;
Переменная
_
,, не вводится. Есть всего два случая использования сброса.Если, однако, идентификатор
_
существует в области действия, то сбросы использовать нельзя:var _ = 42; _ = "hello"; // error - a string cannot explicitly convert from string to int
Исключение составляют случаи, когда
_
переменная используется как выходная переменная. В этом случае компилятор игнорирует тип илиvar
и рассматривает его как сброс:if (p.GetCoordinates(out double x, out double _)) { _ = "hello"; // works fine. Console.WriteLine(_); // error: _ doesn't exist in this context. }
Обратите внимание, что это происходит только в том случае, если в данном случае используется
out var _
илиout double _
. Просто используйте,out _
а затем он будет рассматриваться как ссылка на существующую переменную_
, если она находится в области видимости, например:string _; int.TryParse("1", out _); // complains _ is of the wrong type
Наконец, эта
*
нотация была предложена на ранних этапах обсуждения отбрасывания, но от_
нее отказались в пользу того, что последняя является более широко используемой нотацией в других языках .источник
_
за того, что последний является ...'_ = 42
«отбросить [s] результат выражения» вводит в заблуждение, потому что_ = 42
само по себе является выражением со значением42
, поэтому фактического отбрасывания не происходит. По-прежнему есть разница, потому что_ = 42;
это тоже утверждение, а42;
не это, что имеет значение в некоторых контекстах._ = 42
не может показать, в чем смысл этого отбрасывания - то есть, когда вам нужно «не сохранять» выражение, но все равно оценивать его, поскольку вы обычно можете оценить (нетривиальный , полезно), без сохранения. Я сам не могу сразу придумать полезный пример (и я не знаю, есть ли он или это просто результат согласованности в грамматике).Другой пример оператора Discard
_
в C # 7 - сопоставление с шаблоном переменной типаobject
вswitch
операторе, который недавно был добавлен в C # 7:Код:
static void Main(string[] args) { object x = 6.4; switch (x) { case string _: Console.WriteLine("it is string"); break; case double _: Console.WriteLine("it is double"); break; case int _: Console.WriteLine("it is int"); break; default: Console.WriteLine("it is Unknown type"); break; } // end of main method }
Этот код будет соответствовать типу и отбрасывать переменную, переданную в
case ... _
.источник
Для более любопытных
Рассмотрим следующий фрагмент
static void Main(string[] args) { //.... int a; int b; Test(out a, out b); Test(out _, out _); //.... } private static void Test(out int a, out int b) { //... }
Вот что происходит:
... 13: int a; 14: int b; 15: 16: Test(out a, out b); 02340473 lea ecx,[ebp-40h] 02340476 lea edx,[ebp-44h] 02340479 call 02340040 0234047E nop 17: Test(out _, out _); 0234047F lea ecx,[ebp-48h] 02340482 lea edx,[ebp-4Ch] 02340485 call 02340040 0234048A nop ...
Как вы можете видеть за сценой, два звонка делают одно и то же.
Как отметил @ Servé Laurijssen, круто то, что вам не нужно предварительно объявлять переменные, что удобно, если вас не интересуют некоторые значения.
источник
По поводу первого вопроса
Новинка в том, что вам больше не нужно объявлять
_
внутри или снаружи выражения, и вы можете просто ввестиint.TryParse(s, out _);
Попробуйте сделать это одним лайнером до C # 7:
private void btnDialogOk_Click_1(object sender, RoutedEventArgs e) { DialogResult = int.TryParse(Answer, out _); }
источник
SomeMethod(out _, out _, out three)
имеет 3 выходных параметра, но я отбрасываю первые два без необходимости создавать такие переменные, какunused1, unused2
и т. Д.if (SomeMethod(out _, out _, out _)) _ = 5;
К_
чему это относится?_
вообще, даже если бы вы использовалиout var _
. Кажется, что подчеркивание сделано специально, чтобы отбросить результат.В C # 7.0 (Visual Studio 2017 примерно в марте 2017 г.) сбросы поддерживаются в назначениях в следующих контекстах:
Другие полезные заметки
Простой пример: здесь мы не хотим использовать 1-й и 2-й параметры, а нам нужен только 3-й параметр.
Расширенный пример в корпусе переключателя, который также использовал современное сопоставление шаблонов корпуса переключателя ( источник )
switch (exception) { case ExceptionCustom exceptionCustom: //do something unique //... break; case OperationCanceledException _: //do something else here and we can also cast it //... break; default: logger?.Error(exception.Message, exception); //.. break;
}
источник
var _; if (Int.TryParse(str, out _))
Это не одно и то же.
Ваш код выполняет задание.
В C # 7.0 _ не является переменной, он сообщает компилятору отбросить значение
( если вы не объявили _ как переменную ... если вы это сделаете, переменная используется вместо символа сброса)
Пример: вы можете использовать _ как sting и int в одной строке кода :
string a; int b; Test(out a, out b); Test(out _, out _); //... void Test(out string a, out int b) { //... }
источник