rksoftware

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

C# 11 の新機能を確認「 ジェネリック型数値演算のサポート - ユーザー定義の checked 演算子 」

C# 11 の新機能を確認しています。目次は次の記事です。
rksoftware.hatenablog.com

今回は 「 ジェネリック型数値演算のサポート - ユーザー定義の checked 演算子 」。公式 Learn の記事は次です。
learn.microsoft.com

演算子のオーバーロードをする際に、checked 用の演算子を定義できます。

■ 確認

次のようなコードが書けます。

record struct Record(int Value)
{
    public static Record operator +(Record arg1, Record arg2) => new(arg1.Value + arg2.Value);
    public static Record operator checked +(Record arg1, Record arg2) { checked { return new(arg1.Value + arg2.Value); } }
}

ちなみにこのコードは .NET 6 を指定した場合は次のエラーになります。

エラー CS8936 機能 'チェックされたユーザー定義演算子' は C# 10.0 では使用できません。言語バージョン 11.0 以上を使用してください。

■ 実行

実行してみるとこんな感じで確かにそれぞれの + 演算子が使われます。

Console.WriteLine(new Record(100) + new Record(200));               // Record { Value = 1 }
checked { Console.WriteLine(new Record(100) + new Record(200)); }   // Record { Value = 2 }

record struct Record(int Value)
{
    public static Record operator +(Record arg1, Record arg2) => new(1);
    public static Record operator checked +(Record arg1, Record arg2) { checked { return new(2); } }
}

■ checked の動作

checked の場合にオーバーフローを起こしてみましょう。例外がスローされます。

Console.WriteLine(new Record(int.MaxValue) + new Record(1));    // Record { Value = 1 }
try { checked { Console.WriteLine(new Record(int.MaxValue) + new Record(1)); } }
catch(Exception ex) { Console.WriteLine(ex.Message); }          // Arithmetic operation resulted in an overflow.

record struct Record(int Value)
{
    public static Record operator +(Record arg1, Record arg2) => new(arg1.Value + arg2.Value);
    public static Record operator checked +(Record arg1, Record arg2) { checked { return new(arg1.Value + arg2.Value); } }
}

今回は、intchecked 演算を行っているので、勝手に例外になってくれていますが、独自の計算をする場合は独自に例外をスローするようにしましょう。
※ オーバーフローで例外をスローしないなら checked 演算子にする必要がない

■ 覚えておきましょう

この機能は使わない人はほとんど使わない機能かもしれません。しかし他者が書いたコードでオーバーフロー時の挙動が不審な場合に出会うかもしれません。そんな時思い出して対策が行えるように覚えておきましょう。