C#7:Out变量中的下划线(_)和星号(*)

Nik*_*wal 69 c# c#-7.0

我在C#7阅读新出的可变功能在这里.我有两个问题:

  1. 它说

    我们允许"丢弃"作为输出参数,以a的形式_,让你忽略你不关心的参数:

    p.GetCoordinates(out var x, out _); // I only care about x
    
    Run Code Online (Sandbox Code Playgroud)

    问:我想这只是一个信息而不是C#7的新功能,因为我们也可以在C#7.0之前这样做:

    var _;
    if (Int.TryParse(str, out _))
    ...
    
    Run Code Online (Sandbox Code Playgroud)

    或者我在这里遗失了什么?

  2. 当我在同一博客中提到时,我的代码会出错:

    ~Person() => names.TryRemove(id, out *);
    
    Run Code Online (Sandbox Code Playgroud)

    *不是有效的标识符.Mads Torgersen的疏忽我猜?

Dav*_*rno 97

C#7中的丢弃可以在声明变量的任何地方使用,顾名思义 - 丢弃结果.因此丢弃可以与变量一起使用:

p.GetCoordinates(out var x, out _);
Run Code Online (Sandbox Code Playgroud)

它可以用来丢弃表达式结果:

_ = 42;
Run Code Online (Sandbox Code Playgroud)

在这个例子中,

p.GetCoordinates(out var x, out _);
_ = 42;
Run Code Online (Sandbox Code Playgroud)

没有变量_,正在引入.只有两种使用丢弃的情况.

但是,如果_范围中存在标识符,则不能使用丢弃:

var _ = 42;
_ = "hello"; // error - a string cannot explicitly convert from string to int
Run Code Online (Sandbox Code Playgroud)

例外情况是将_变量用作out变量.在这种情况下,编译器会忽略该类型或var将其视为丢弃:

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

请注意,只有在这种情况下out var _out double _使用时才会出现这种情况.只需使用out _然后它被视为对现有变量的引用_,如果它在范围内,例如:

string _;
int.TryParse("1", out _); // complains _ is of the wrong type
Run Code Online (Sandbox Code Playgroud)

最后,*在关于丢弃物的讨论的早期提出了这种符号,_由于后者是其他语言中更常用的符号而被放弃了.

  • 我认为这是隐含的,但丢弃的重点是它的预期值从未被实际存储? (2认同)

Cyb*_*ogs 22

_C#7中Discard运算符的另一个例子是模式匹配语句中的类型变量,objectswitch语句最近在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
}
Run Code Online (Sandbox Code Playgroud)

此代码将匹配类型并丢弃传递给的变量case ... _.


Sid*_*Sid 12

更好奇

请考虑以下代码段

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)
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

这就是发生的事情:

...

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 

...
Run Code Online (Sandbox Code Playgroud)

正如你在幕后看到的那样,这两个电话正在做同样的事情.

正如@ServéLaurijssen指出的那样,很酷的事情是,如果您对某些值不感兴趣,则不必预先声明变量.

  • IL*具有*是相同的,因为您调用的函数仍然需要out变量的插槽.只是使用新的丢弃语法允许编译器进一步假设局部变量(或者更确切地说是缺少),允许它更有效地使用它(至少在理论上;我不知道是否已经有任何优化在编译器中截至目前). (3认同)

Ser*_*sen 9

关于第一个问题

我想这只是一个信息而不是C#7的新功能,因为我们也可以在C#7.0之前这样做.

var _;
if (Int.TryParse(str, out _))
    // ...
Run Code Online (Sandbox Code Playgroud)

新颖性是你不必_在表达式内外声明,你只需键入即可

int.TryParse(s, out _);
Run Code Online (Sandbox Code Playgroud)

尝试在C#7之前做一个班轮:

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

  • 要添加:下划线对于具有多个输出参数的方法非常有效,例如,`SomeMethod(out _,out _,out three)`有3个输出参数,但是我扔掉前两个而不必创建像`unused1,unused2`等 (7认同)
  • @NikhilAgrawal即使你使用`out var _`,也根本就没有`_`变量.看起来下划线特别容易丢掉结果. (4认同)