C#14新機能

C#14 新機能 B05_型パラメータありのextensionブロックの書き方

今回は、型パラメータを持つ拡張メソッドを extension ブロックで書き直す方法を見ていきます。題材は、コレクションが空かどうかを判定する IsEmpty という拡張メソッドです。

書き換え前のコード

書き換え前は、従来どおりの static メソッドとして定義された拡張メソッドです。第一引数に this を付けた IEnumerable<T> を受け取り、型パラメータ T は IsEmpty メソッド自身が持っています。

図:書き換え前の IsEmpty<T> 拡張メソッド。this IEnumerable<T> list を第一引数に取る static メソッドとして定義されている。

public static bool IsEmpty<T>(this IEnumerable<T> list)
{
  if (list == null) return true;
  return !list.Any();
}

extension ブロックを追加する

まず、メソッドの上に extension() と書き、丸カッコを付けます。この丸カッコの中に、これまで拡張メソッドの第一引数(this を除いた部分)に書いていた型を移していきます。

図:メソッドの上に extension() を追加したところ。

続けて、中カッコ { } を書いてブロックにし、IsEmpty メソッドの第一引数だった IEnumerable<T> list を extension の丸カッコの中に移動します。

図:extension(IEnumerable<T> list) { … } という形にブロック化したところ。IsEmpty メソッドはこのブロックの中に含まれる。

static と this 引数を取り除く

拡張メソッド側の第一引数はすでに extension ブロックのほうに吸収されているため、IsEmpty メソッドの static 修飾子と、this を含む第一引数(this IEnumerable<T> list)はどちらも不要になります。まず static を消します。

図:IsEmpty メソッドから static を削除したところ。

続けて、第一引数の this IEnumerable<T> list もまとめて削除します。これで IsEmpty は引数を取らない、普通のインスタンスメソッドになります。

図:this IEnumerable<T> list を削除し、IsEmpty<T>() という引数なしのメソッドになったところ。

型パラメータを extension 側に移動する

最後に型パラメータです。今は IsEmpty<T> という形で、IsEmpty メソッド自身が型パラメータ T を持っていますが、この T を extension の後ろ(extension<T>)に書き直します。そうすると、IsEmpty 側の <T> はもう不要になるので削除します。

図:型パラメータ T を extension<T>(IEnumerable<T> list) の形で extension 側に移したところ。IsEmpty<T>() の <T> はまだ残っている。

図:IsEmpty 側の <T> も削除し、書き換えが完了した状態。extension<T>(IEnumerable<T> list) ブロックの中に、引数なしのインスタンスメソッド IsEmpty() がある。

extension<T>(IEnumerable<T> list)
{
  public bool IsEmpty()
  {
    if (list == null) return true;
    return !list.Any();
  }
}

呼び出し側は変更不要

extension ブロックで書き直しても、呼び出し側のコードはこれまでとまったく同じです。listA.IsEmpty() のように、今まで通り呼び出すことができます。

図:呼び出し側のコード。listA.IsEmpty() のように変更前と同じ書き方で呼び出せる。

実際にデバッグ実行して確認すると、要素を1件追加した listA では retA が false、空のままの listB・listC では retB・retC がともに true となり、書き換え前と同じ結果が得られていることが分かります。

図:ウォッチウィンドウでの実行結果。retA は false、retB と retC は true。

このように、型パラメータを持つ拡張メソッドを extension ブロックで書く場合は、型パラメータを extension の後ろに、引数を extension の丸カッコの中に書き、メソッド本体は static を外した普通のインスタンスメソッドとして書きます。同じ要領で、ぜひ他の拡張メソッドも extension ブロックに書き換えてみてください。

C#14 新機能