2022年5月30日月曜日

プロパティパターン in C# 10.0

どうも、もりもりです。

今回はC# 10.0で改良されたパターンマッチングのプロパティパターンをちょこっと触ってみました。

プロパティパターン (C# 8.0)

まずはC# 8.0で使用できるようになったプロパティパターンのサンプルです。
プロパティパターンは、プロパティに対して再起的にマッチングを行うパターンです。 プロパティだけでなくフィールドにも使用できます。

例えば、下記のようなPointクラスのXとYによって返す値を決定したいコードがあったとします。

static int GetScore(Point p)
{
    if (p.X == 1 && p.Y == 2)
    {
        return 0;
    }
    else if (p.X > 0)
    {
        return p.X;
    }
    else
    {
        return -1;
    }
}

上記のコードを、プロパティパターンを使用すると下記のように書くことができます。
(switch式でさらに簡潔にしてます。

static int GetScore(Point p)
    => p switch
{
    { X: 1, Y: 2 } => 0,
    { X: var x, Y: _ } when x > 0 => x,
    _ => -1
};

呼び出し側はこんな感じで。

var p1 = new Point(1, 2);
var score = GetScore(p1);
Console.WriteLine($"p1 score : {score}");

var p2 = new Point(10, 10);
score = GetScore(p2);
Console.WriteLine($"p2 score : {score}");

var p3 = new Point(-3, 0);
score = GetScore(p3);
Console.WriteLine($"p3 score : {score}");

結果はこうなります。

p1 score : 0
p2 score : 10
p3 score : -1

C# 10.0での拡張

このプロパティパターンですが、入れ子のプロパティやフィールド参照で書けるようになったみたいです。

下記のようなクラスがあったとします。

class Item
{
    public string Name { get; set; }
    public Attribute Attribute { get; set; }
}

class Attribute
{
    public bool? A { get; set; } 
}

ItemクラスのNameの文字列長をチェックしたい場合、 下記のように{ Name.Length: 1 }と書けるようになりました。

var item1 = new Item() { Name = "A", };
if (item1 is { Name.Length: 1 })
{
    Console.WriteLine($"single char");
}

また、下記のようにAttributeクラスをnewしてると 「A is null」の方を通りますが、Attributeのプロパティに何もセットしない場合は 「A is not null」の方を通ります。これは{ Attribute.A: ・・・ }と書いても、まずAttributeオブジェクトのnullチェックをしているためです。

var item2 = new Item() { Name = "ABC", Attribute = new Attribute() { }, };
if (item2 is { Attribute.A: null })
{
    Console.WriteLine($"A is null");
}
else
{
    Console.WriteLine($"A is not null");
}

自分用のメモとして残しているのでちょっと分かりにくいかもですが、より簡潔にコードを書けるようになっているのだなということはなんとなく分かっていただけたかと。 掘り下げてみたい方はすみませんがググってみてください。

以上、もりもりでした。

0 件のコメント:

コメントを投稿