rksoftware

Visual Studio とか C# とかが好きです

C# 8 の確認 - プロパティのパターン

今回は プロパティのパターン 。この機能でようやくパターンマッチングという名前で想像される機能となったのではないでしょうか?

公式はこちら

このブログでの目次?はこちら

プロパティの値でマッチ

プロパティの値でマッチできます。一部のプロパティだけも可能。
次の例では、1 が出力されます。

var point = new Point(1, 2);
var x = point switch
{
    Point { X: 0, Y: 2 } => 0,
    Point { X: 2, Y: 3 } => 2,
    Point { X: 1, Y: _ } => 1,
    _ => -1
};

// 1 が出力される
Console.WriteLine(x);

一つ目の

Point { X: 0, Y: 2 }

は X が 0、Y が 2 の場合にマッチします。

二つ目の

Point { X: 2, Y: 3 }

は X が 2、Y が 3 の場合にマッチします。

三つ目の

Point { X: 1, Y: _ }

_ はワイルドカードです。何にでもマッチします。X が 1、Y は何であってもマッチします。

最後の

_

は default です。それまでのどの条件にもマッチしない場合にマッチします。

ちなみに新機能が出るたびに、速度のためと言って以前までの機能だけで実装することにこだわる方がいます。
この機能では、「条件式の分いくつもインスタンスが生まれる」や「条件の判定の度にプロパティアクセスがされる」と考えて使うのを避けようとする方も出てくると思います。そこは大丈夫です。条件のためにインスタンス化はされませんし、プロパティにも複数回アクセスするコードにはなりません。心配される方にも安心して使わせてください。

例えば次のコードでもそれは確認できます。

class Program
{
    struct Point
    {
        public Point(int x, int y)
        {
            Console.WriteLine("ctor");
            _x = x; _y = y;
        }

        int _x;
        public int X
        {
            get { Console.WriteLine("getterX"); return _x; }
            set { Console.WriteLine("setterX"); _x = value; }
        }

        int _y;
        public int Y {
            get { Console.WriteLine("getterY"); return _y; }
            set { Console.WriteLine("setterY"); _y = value; }
        }
    }

    static void Main(string[] args)
    {
        var point = new Point(1, 2);
        var x = point switch
        {
            Point { X: 0, Y: 2 } => 0,
            Point { X: 2, Y: 3 } => 2,
            Point { X: 1, Y: _ } => 1,
            _ => -1
        };

        Console.WriteLine(x);
        // 出力
        // ctor
        // getterX
        // 1
    }
}