Подтвердить что ты не робот

С# 7: Подчеркивание (_) & Star (*) в переменной Out

Я читал о новых возможностях переменных в С# 7 здесь. У меня есть два вопроса:

  1. Это говорит

    Мы также разрешаем "отбрасывать" как параметры out, в форме _, чтобы позволить вам игнорировать параметры, которые вас не интересуют:

    p.GetCoordinates(out var x, out _); // I only care about x
    

    Q: Я думаю, это просто информация, а не новая функция С# 7, потому что мы можем сделать это и в С# 7.0:

    var _;
    if (Int.TryParse(str, out _))
    ...
    

    или я что-то здесь упускаю?

  2. Мой код выдает ошибку, когда я делаю, как указано в том же блоге:

    ~Person() => names.TryRemove(id, out *);
    

    * не является допустимым идентификатором. Полагаю, Мэдс Торгерсен, наверное, недосмотр?

4b9b3361

Ответ 1

Отбрасывает, в С# 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

Исключением является случай, когда переменная _ используется как переменная out. В этом случае компилятор игнорирует тип или var и рассматривает его как сброс:

if (p.GetCoordinates(out double x, out double _))
{
    _ = "hello"; // works fine.
    Console.WriteLine(_); // error: _ does not exist in this context.
}

Обратите внимание, что это происходит только в том случае, если в этом случае используется out var _ или out double _. Просто используйте out _, а затем он будет рассматриваться как ссылка на существующую переменную, _, если она находится в области видимости, например:

string _;
int.TryParse("1", out _); // complains _ is of the wrong type

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

Ответ 2

Другой пример оператора сброса _ в С# 7 - это сопоставление с образцом переменной типа object в операторе switch, который недавно был добавлен в С# 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 ... _.

Ответ 3

Для более любопытных

Рассмотрим следующий фрагмент

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, дело в том, что вам не нужны переменные pre-declare, которые удобны, если вас не интересуют некоторые значения.

Ответ 4

Относительно первого вопроса

Я думаю, это просто информация, а не новая функция С# 7, потому что мы можем сделайте это и в pre С# 7.0.

var _;
if (Int.TryParse(str, out _))
    // ...

Новизна в том, что вам больше не нужно объявлять _ внутри или вне выражения, и вы можете просто ввести

int.TryParse(s, out _);

Попробуйте сделать это один лайнер pre С# 7:

private void btnDialogOk_Click_1(object sender, RoutedEventArgs e)
{
     DialogResult = int.TryParse(Answer, out _);
}

Ответ 5

В С# 7.0 (Visual Studio 2017 вокруг марта 2017 г.) отбрасывания поддерживаются в назначениях в следующих контекстах:


Другие полезные заметки

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

Простой пример: здесь мы не хотим использовать 1-й и 2-й параметры, нам нужен только 3-й параметр

(_, _, area) = city.GetCityInformation(cityName);

Продвинутый пример в случае коммутатора, в котором также используется современное сопоставление с шаблоном коммутатора (источник)

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;

}