C#14新機能

C#14 新機能 B08_拡張演算子

extension ブロックでは、メソッドやプロパティだけでなく、演算子のオーバーロードも書くことができます。まずは通常のクラスに対する演算子のオーバーロードの書き方を確認し、その後で extension ブロックに書き換える流れを見ていきます。

演算子のオーバーロードとは

クラスに対して演算子を追加しておくことを、演算子のオーバーロードと呼びます。例えば次のような Money クラスを考えます。

public class Money
{
  public int Value { get; set; }
}

 

この Money クラスのインスタンスを2つ作成し、それぞれの Value に値を入れます。

var m1 = new Money();
m1.Value = 111;
var m2 = new Money();
m2.Value = 222;

 

図1 Money クラス(Value プロパティのみ)

この状態で m1 + m2 のように m1 と m2 を足すことはできません。「何を足すのか」がコンパイラに定義されていないため、コンパイルエラーになります。

図2 m1 + m2 はコンパイルエラーになる

演算子のオーバーロードを定義する

ここに演算子のオーバーロードを定義しておけば、「足すとはこういう処理をすること」をあらかじめ書いておくことができます。書き方は public static で戻り値の型を書き、続けて operator キーワードと演算子を書きます。今回は + 演算子を定義します。

public static int operator +(Money a, Money b)
{
}

 

図3 operator +(Money a, Money b) のシグネチャ

+ 演算子が使われたときにどのような処理をするかを、このメソッドの中に書いていきます。今回は Money の a と b を受け取り、それぞれの Value 同士を足したものを返すようにします。

public static int operator +(Money a, Money b)
{
  return a.Value + b.Value;
}

 

図4 a.Value と b.Value を足して返す実装

m1 + m2 のとき、m1 が引数 a に、m2 が引数 b になります。つまり「a に b が足されたときは Value 同士を足してね」という定義です。これでコンパイルエラーは解消され、m1 + m2 の結果を mm に代入する次のコードが実行できるようになります。

var mm = m1 + m2;

 

デバッグ実行して mm の値を確認すると、333 になっています。m1.Value(111)と m2.Value(222)を足した結果が正しく返っていることが分かります。

図5 デバッグ実行で mm の値が 333 になることを確認

なお、戻り値の型は int でなければならないわけではありません。a の Value と b の Value を足した値で新しく Money クラスのインスタンスを作り、それを返却するといった実装にすることもできます。

extension ブロックで書く

ここまでは Money クラスを自分で作っていたので、演算子のオーバーロードを直接クラスに書くことができました。しかしこれがマイクロソフトのクラスライブラリやサードパーティのクラス、あるいは自分たちが作ったものでも DLL を参照しているようなものなど、変更できないコードだった場合は、このようには書けません。

そのような変更できないコードに対して拡張したい場合は、この演算子のオーバーロードも extension ブロックの中に書くことができます。引数を Money にした extension ブロックを用意し、その中に先ほどと同じ内容をそのまま書きます。

extension(Money money)
{
  public static int operator +(Money a, Money b)
  {
    return a.Value + b.Value;
  }
}

 

図6 extension(Money money) ブロックを新設

図7 extension ブロック内に operator + を実装した状態

Money クラス側に書いていた演算子のオーバーロードは削除していますが、これでもコンパイルは通ります。実行すると、こちらも 333 という結果になり、extension ブロックの中に書いた演算子オーバーロードがちゃんと動作していることが分かります。

図8 extension ブロック版でも同じ結果(333)になることを確認

このように、演算子のオーバーロードも extension ブロックに書けるようになったというのが今回のポイントです。

C#14 新機能