拡張メソッド(Extension Methods)を理解しよう!

[C#] 拡張メソッド(Extension Methods)を理解しよう!

※ 当サイトは広告を含みます。

ここではC#の拡張メソッドを学習します。

拡張メソッド(Extension Methods)

拡張メソッドとは、既存のクラスにメソッドを追加できる機能です。

継承を利用すれば既存クラスに機能を追加することができますが、その場合は別クラスになります。
対して拡張メソッドの場合、元のクラスに新規メソッドが増えたような扱いになります。

最初に次のようなクラスがあったとします。
単にプロパティが2個と表示用のメソッドを所有します。


namespace Sample
{
  public class Data
  {
    public int X { get; set; }
    public int Y { get; set; }

    public void Display()
    {
      Console.WriteLine($"X={this.X}, Y={this.Y}");
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      var data = new Data()
      {
        X = 2,
        Y = 8,
      };

      data.Display();
    }
  }
}

拡張メソッドを利用してクラスの機能を増やしたいと思います。
何でもいいと思いますが、ここではプロパティの値を入れ替える機能を追加します。

結論として、こんな感じに記述するのが拡張メソッドです。


namespace Sample
{
  // 拡張メソッドの利用に必要
  using ExtensionMethods;

  public class Data
  {
    public int X { get; set; }
    public int Y { get; set; }

    public void Display()
    {
      Console.WriteLine($"X={this.X}, Y={this.Y}");
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      var data = new Data()
      {
        X = 2,
        Y = 8,
      };

      data.Display();

      // 拡張メソッドを利用する
      data.Swap();

      data.Display();
    }
  }
}

namespace ExtensionMethods
{
  // 拡張メソッド用のクラス
  public static class Extensions
  {
    // 拡張メソッド
    public static void Swap(this Sample.Data data)
    {
      var tmp = data.X;
      data.X = data.Y;
      data.Y = tmp;
    }
  }
}

先に該当箇所を抜粋します。


namespace ExtensionMethods
{
  // 拡張メソッド用のクラス
  public static class Extensions
  {
    // 拡張メソッド
    public static void Swap(this Sample.Data data)
    {
      var tmp = data.X;
      data.X = data.Y;
      data.Y = tmp;
    }
  }
}

もう少し拡大します。


// 拡張メソッド
public static void Swap(this Sample.Data data)
{
  var tmp = data.X;
  data.X = data.Y;
  data.Y = tmp;
}

static必須で引数にthisで型を指定するのが拡張メソッドの記述方法です。
こんな感じに記述すると、対象とするクラスが拡張されてメソッドが増えます。


public static void Swap(this 型 引数)

今回は実用パターンを想定して、拡張メソッドを該当クラスとは別の名前空間に記述しました。
拡張メソッド自体は該当するクラスと同じ名前空間にも書けますが、そうすることは稀です。

理由は拡張メソッドを追加する場合の殆どが、.NET外部ライブラリに存在するクラスを対象にするからです。
つまり、自分がアクセス不可能なソースコードが対象です。よって、同一の名前空間に記述することは少ないです。

合わせて利用時の注意ですが、拡張メソッドを記述した名前空間をusing宣言しないと拡張メソッドは使えません。


// 拡張メソッドの利用に必要
using ExtensionMethods;

そうすれば普通のメソッドと同じように使えます。


// 拡張メソッドを利用する
data.Swap();

継承 or 拡張メソッド

機能を追加するなら継承でも問題ありません。もしくは既存のクラス自体を直接改造します。
と言うのも、拡張メソッドは万能ではないので、必ずしも追加したい機能が記述できるとは限りません。

りさ
りさ

どういうこと?

管理人
管理人

拡張メソッドは機能が増えてるんじゃなく、拡張メソッドを経由して既存クラスにアクセスしてるだけだから。

つまり、拡張メソッドで機能追加できる範囲は既存クラスの公開範囲のみです。

先程の例であれば、値がプロパティとして公開してあったのでアクセスできました。
仮に値が非公開領域、private指定のフィールドだった場合、アクセス不可能なために改造できません。

では、どんな時に活躍するのかと言うと、前述した通り.NET外部ライブラリを拡張する時に使います。
滅多にありませんが.NET側のクラスに凄く簡単な機能を追加する場合に使うことがあります。

ライブラリ側のクラスに依存する機能を1個だけ増やしたいけど継承は手間って場合ですかね。
同種の機能を2個も3個も追加したいなら、まず継承を検討するほうがいいです。
拡張メソッドの利点は既存クラスのメソッドのように利用できること、これが利点にならないなら無意味です。

なお、既存クラスがstaticsealedなど、そもそも継承できない場合は拡張メソッドが活躍します。
あくまで拡張メソッドを経由したアクセスなので、こういう制限も無視することができます。

りさ
りさ

使う場面が難しそうですね。

管理人
管理人

あんまり使わない説。

あとがき

LINQが拡張メソッドなので、作らなくても使うことはあります。
と言うか、拡張メソッドって殆どLINQ専用機能では。

◆ C#に関する学習コンテンツ

この記事は参考になりましたか?

関連記事

コメント

この記事へのコメントはありません。