web-dev-qa-db-ja.com

C#7:Out変数のアンダースコア(_)&スター(*)

C#7の新しいout変数機能について読んでいました here 。 2つの質問があります。

  1. それは言います

    _の形式で「破棄」することもできます。これは、気にしないアウトパラメーターを無視できるようにするためです。

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

    Q:これは単なる情報であり、C#7の新しい機能ではないようです。

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

    または私はここで何かが欠けていますか?

  2. 同じブログで言及されているようにコードを実行するとエラーが発生します。

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

    *は有効な識別子ではありません。 Mads Torgersenによる監視だと思いますか?

65
Nikhil Agrawal

Discards 、C#7では、変数が宣言されている場所であればどこでも使用できます。名前が示すとおり、結果を破棄します。したがって、廃棄はout変数で使用できます。

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

また、式の結果を破棄するために使用できます。

_ = 42;

例では、

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

導入される変数_はありません。使用されている廃棄のケースは2つだけです。

ただし、スコープに識別子_が存在する場合、破棄は使用できません。

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: _ doesn't exist in this context.
}

これは、この場合、out var _またはout double _が使用されている場合にのみ発生することに注意してください。 out _を使用するだけで、スコープ内にある場合は、既存の変数_への参照として扱われます。例:

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

最後に、*表記法は破棄に関する議論の初期に提案されました しかし、他の言語でより一般的に使用される表記法であるため、_を支持して放棄されました

93
David Arno

C#7の破棄演算子_の別の例は、C#7で最近追加されたobjectステートメントのswitch型の変数 パターンマッチ

コード:

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 ... _に渡された変数を破棄します。

21
Cyber Progs

もっと知りたい

次のスニペットを検討してください

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 

...

背後でわかるように、2つの呼び出しは同じことをしています。

@ServéLaurijssenが指摘したように、クールなことはpre-declare変数を必要としないことです。これは、値に興味がない場合に便利です。

12
Sid

最初の質問について

これは単なる情報であり、C#7の新機能ではないと思います。C#7.0以前でも同様のことができるからです。

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

斬新な点は、式の内側または外側で_を宣言する必要がなくなり、入力するだけで済むことです。

int.TryParse(s, out _);

C#7の前にこの1つのライナーを試してください:

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