web-dev-qa-db-fra.com

C # 7: Soulignement (_) et étoile (*) dans la variable Out

Je lisais de nouvelles fonctionnalités variables en C # 7 ici . J'ai deux questions:

  1. Ça dit

    Nous autorisons également les "rejets" comme paramètres de sortie, sous la forme d'un _, pour vous permettre d’ignorer les paramètres qui vous intéressent:

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

    Q: Je suppose que c'est simplement une info et non une nouvelle fonctionnalité de C # 7 car nous pouvons le faire dans les versions antérieures à C # 7.0:

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

    ou est-ce que je manque quelque chose ici?

  2. Mon code donne une erreur quand je fais comme mentionné dans le même blog:

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

    * n'est pas un identifiant valide. Un oubli de Mads Torgersen, je suppose?

65
Nikhil Agrawal

Discards , dans C # 7, peut être utilisé partout où une variable est déclarée, pour - comme son nom le suggère - pour ignorer le résultat. Donc, un rejet peut être utilisé avec les variables out:

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

et il peut être utilisé pour ignorer un résultat d'expression:

_ = 42;

Dans l'exemple,

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

Il n'y a pas de variable, _, en cours d'introduction. Il n'y a que deux cas d'utilisation d'un rejet.

Si toutefois, un identifiant _ existe dans la portée, les rejets ne peuvent pas être utilisés:

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

L'exception à ceci est quand un _ variable est utilisée comme variable de sortie. Dans ce cas, le compilateur ignore le type ou var et le traite comme une suppression:

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

Notez que cela ne se produit que si, dans ce cas, out var _ ou out double _ est utilisé. Il suffit d'utiliser out _ puis il est traité comme une référence à une variable existante, _, si c'est dans la portée, par exemple:

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

Finalement, le * La notation a été proposée au début des discussions sur les rejets, mais a été abandonnée au profit de _, cette dernière étant une notation plus couramment utilisée dans d’autres langues .

93
David Arno

Un autre exemple de l'opérateur de rejet _ en C # 7 est correspondance de modèle une variable de type object dans une instruction switch récemment ajoutée en C # 7:

Code:

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
}

Ce code correspond au type et ignore la variable transmise à la case ... _.

21
Cyber Progs

Pour plus curieux

Considérez l'extrait suivant

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

C'est ce qui se passe:

...

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 

...

Comme vous pouvez le voir en coulisse, les deux appels font la même chose.

Comme @ Servé Laurijssen l'a souligné, la chose intéressante est que vous n'avez pas à pré-déclarer variables, ce qui est pratique si vous n'êtes pas intéressé par certaines valeurs.

12
Sid

Concernant la première question

Je suppose que ceci est juste une info et pas une nouvelle fonctionnalité de C # 7 car nous pouvons le faire dans les versions antérieures à C # 7.0.

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

La nouveauté est que vous n'avez pas à déclarer _ plus à l'intérieur ou à l'extérieur de l'expression et vous pouvez simplement taper

int.TryParse(s, out _);

Essayez de faire cette ligne avant C # 7:

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