C # 7: Subrayado () y Estrella ( * ) en la variable Out


Estaba leyendo sobre nuevas características variables en C#7 aquí. Tengo dos preguntas:

  1. Dice:

    También permitimos "descartes" como parámetros de salida, en forma de _, para permitirle ignorar los parámetros que no le importan:

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

    P: Supongo que esto es solo una información y no una nueva característica de C # 7 porque también podemos hacerlo en pre C # 7.0:

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

    O me estoy perdiendo algo aquí?

  2. Mi código da un error cuando lo hago como se menciona en el mismo blog:

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

    * no es un identificador válido. Un descuido de Mads Torgersen, supongo.

 50
Author: Nikhil Agrawal, 2017-03-21

4 answers

Los descartes, en C#7 se pueden usar donde se declare una variable, para - como su nombre indica - descartar el resultado. Por lo tanto, se puede usar sin variables:

p.GetCoordinates(out var x, out _);

Y se puede usar para descartar un resultado de expresión:

_ = 42;

En el ejemplo,

p.GetCoordinates(out var x, out _);
_ = 42;

No se introduce ninguna variable, _. Solo hay dos casos de un descarte que se está utilizando.

Sin embargo, si existe un identificador _ en el ámbito, entonces los descartes no pueden ser usado:

var _ = 42;
_ = "hello"; // error - a string cannot explicitly convert from string to int

La excepción a esto es cuando una variable _ se usa como una variable out. En este caso, el compilador ignora el tipo o var y lo trata como un descarte:

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

Tenga en cuenta que esto solo ocurre si, en este caso, se usa out var _ o out double _. Simplemente use out _ y luego se trata como una referencia a una variable existente, _, si está en el alcance, por ejemplo:

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

Finalmente, la notación * se propuso al principio de las discusiones sobre los descartes, pero fue abandonado a favor de _ debido a que este último es una notación más utilizada en otros idiomas .

 73
Author: David Arno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-27 12:33:44

Para más curiosos

Considere el siguiente fragmento

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)
{
    //...
}

Esto es lo que está sucediendo:

...

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 

...

Como se puede ver detrás de la escena las dos llamadas están haciendo lo mismo.

Como @Servé Laurijssen señaló, lo bueno es que no tienes que pre-declarar variables, lo cual es útil si no estás interesado en algunos valores.

 10
Author: Sid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-21 11:03:23

Otro ejemplo del Operador de descarte _ en C # 7 es pattern match una variable de tipo object en una instrucción switch, que se agregó recientemente en C # 7:

Código:

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
        }

Este código coincidirá con el tipo y descartará la variable pasada a case ... _.

 9
Author: Cyber Progs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-27 12:37:37

Sobre la primera cuestión

Supongo que esto es solo una información y no una nueva característica de C#7 porque podemos hazlo también en pre C # 7.0.

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

La novedad es que ya no tienes que declarar _ dentro o fuera de la expresión y solo tienes que escribir

int.TryParse(s, out _);

Trata de hacer este liner pre C # 7:

private void btnDialogOk_Click_1(object sender, RoutedEventArgs e)
{
     DialogResult = int.TryParse(Answer, out _);
}
 8
Author: Serve Laurijssen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-21 07:39:49