rksoftware

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

C# 14 を改めて確認しよう! 最新動画での発見 演算子オーバーロード

C# 14 を使いたい! そう思っていますね? わかります。私もです。

.NET 10 ももうリリースになります。となれば当然に皆さんお待ちかねの C# 14 を皆が使い始めます。私も使います。

■ 前回までの C# 14

C# 14 の新機能ですが、前回までの記事で機能リスト的には Preview 版の時に追いかけていた内容とほぼ同じ、コードもほぼそのまま、ほぼ何もしなくてもビルドできるとわかりました。

■ C# 14 の動画

こちらで C# 14 が語られています。

www.youtube.com

その中で気になることを知りました。

■ 知った機能を使ったコード

Console.WriteLine((new A { MyProperty = 10 } - new A { MyProperty = 3 }).MyProperty); // 出力は 「7」

class A
{
    public int? MyProperty { get; set; }
}

static class Ex2
{
    extension(A)
    {
        public static A operator -(A a, A b) => new A { MyProperty = a?.MyProperty - b?.MyProperty };
    }
}

新しい拡張メンバーの書き方で演算子を定義できます。

■ 演算子オーバーロード

演算子オーバーロードの公式ドキュメントはこちらです。

learn.microsoft.com

観てお分かりの通り、演算子オーバーロードは左辺のクラスに 左辺・右辺の値を引数にとる static メソッドを定義ています(二項演算子の場合)。
こんな感じです。

class A
{
    public int? MyProperty { get; set; }
    public static A operator -(A a, A b) => new A { MyProperty = a?.MyProperty - b?.MyProperty };
}

■ これまでの拡張メソッド

今回演算子オーバーロードは拡張メンバーで書けるとのことですので、昔からの拡張メソッドでも書けたのか? と思い試しに書いてみました。すると驚きの結果に。
なんと! ダメでした。

static class Ex1
{
    // これはエラー 「'Ex1.operator -(A, A)': 静的クラスにユーザー定義の演算子を含めることはできません」
    public static A operator -(A a, A b) => new A { MyProperty = a?.MyProperty - b?.MyProperty };
    // これはエラー 「キーワード 'this' は現在のコンテキストでは使用できません」
    public static A operator *(this A a, A b) => new A { MyProperty = a?.MyProperty * b?.MyProperty };
}

■ あたらしい拡張メンバー

ちなみに拡張メンバーにも複数の機能があります。型にスタティックメソッドを追加する機能と、インスタンスメンバーを追加する機能です。
結論として、インスタンスメンバーのパターンはダメでした。

static class Ex2
{
    // これはエラー 「オーバーロード可能な単項演算子が必要です」
    extension(A a)
    {
        // これはエラー 「User-defined operator 'Ex2.extension(A).operator *(A)' must be declared static and public」
        public A operator *(A b) { return new A { MyProperty = a.MyProperty - b?.MyProperty }; }
    }
}

■ これは使えるが

この拡張メンバーでオペレーターオーバーロードする機能・書き方、クラスがごちゃごちゃせずよさそうです。使っていきたい。
問題は、オペレーターオーバーロードをする機会が私には皆無だという点ですが。