bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] 拡張メソッド(Extension Methods)の使い方

[C#] 拡張メソッド(Extension Methods)の使い方

Jun 7, 2026 C# , .NET bucket-sort

既存のクラスやインターフェースのソースコードを変更できない状況でも、拡張メソッド(Extension Methods) を使えばメソッドを追加しているかのように見せることができます。

LINQ の Where や Select も拡張メソッドとして定義されており、C# の中でも特によく使われる機能です。

この記事では次の 5 つを順に説明します。

  1. 拡張メソッドの定義
  2. 拡張メソッドの呼び出し
  3. 拡張メソッドのインポート
  4. 特定のインターフェースを実装した型への拡張
  5. GetEnumerator の拡張メソッドサポート(C# 9.0)

拡張メソッドの定義

拡張メソッドは、static クラスの中に static メソッドとして定義します。第 1 引数に this キーワードを付けることで、その型に対する拡張メソッドとして認識されます。

namespace MyExtensions;

public static class StringExtensions
{
    // string 型に IsNullOrEmpty メソッドを追加する
    public static bool IsNullOrEmpty(this string s)
        => string.IsNullOrEmpty(s);

    // string 型に Reverse メソッドを追加する
    public static string Reverse(this string s)
    {
        char[] chars = s.ToCharArray();
        Array.Reverse(chars);
        return new string(chars);
    }

    // string 型に WordCount メソッドを追加する
    public static int WordCount(this string s)
        => s.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length;
}

ポイントは 3 つです。

  • 定義するクラスは static class にする
  • メソッド自体も static にする
  • 第 1 引数を this 対象の型 パラメーター名 の形で書く

この this が付いた引数が「このメソッドを追加したい型」を指定しています。

拡張メソッドの呼び出し

定義した拡張メソッドは、インスタンスメソッドと同じ記法 で呼び出せます。

string message = "Hello World from C#";

// インスタンスメソッドのように呼び出せる
Console.WriteLine(message.IsNullOrEmpty()); // False
Console.WriteLine(message.Reverse());       // #C morf dlroW olleH
Console.WriteLine(message.WordCount());     // 4

string empty = "";
Console.WriteLine(empty.IsNullOrEmpty());   // True

通常のメソッドと同じように、静的メソッドとして呼び出すこともできます。

// 静的メソッドとしての呼び出し(同じ動作)
Console.WriteLine(StringExtensions.WordCount(message)); // 4

通常は前者のインスタンスメソッド形式で書くほうが読みやすいため、そちらが一般的です。

拡張メソッドのインポート

拡張メソッドを使うには、定義されている名前空間を using でインポートする 必要があります。

MyApp/
├── Extensions/
│   └── StringExtensions.cs  (namespace MyApp.Extensions)
└── Program.cs
// StringExtensions.cs
namespace MyApp.Extensions;

public static class StringExtensions
{
    public static bool IsPalindrome(this string s)
    {
        string reversed = new string(s.Reverse().ToArray());
        return s.Equals(reversed, StringComparison.OrdinalIgnoreCase);
    }
}
// Program.cs
using MyApp.Extensions; // この using がないと IsPalindrome は使えない

string word = "racecar";
Console.WriteLine(word.IsPalindrome()); // True

string other = "hello";
Console.WriteLine(other.IsPalindrome()); // False

using を書かない状態で拡張メソッドを呼び出そうとすると、コンパイラは「そのメソッドは存在しない」というエラーを出します。プロジェクト全体で使いたい場合は global using を使うと便利です。

// global_usings.cs などのファイルに記述
global using MyApp.Extensions;

特定のインターフェースを実装した型への拡張

拡張メソッドの第 1 引数にインターフェース型を指定すると、そのインターフェースを実装するすべての型に対して メソッドを追加できます。これは LINQ の設計でも使われているパターンです。

ここでは IEnumerable<T> を実装する型に対して拡張メソッドを追加します。

using System.Collections.Generic;
using System.Linq;

public static class EnumerableExtensions
{
    // IEnumerable<int> を実装するすべての型に Sum2 を追加
    public static int Sum2(this IEnumerable<int> source)
    {
        int total = 0;
        foreach (var item in source)
            total += item;
        return total;
    }

    // IEnumerable<T> を実装するすべての型に IsEmpty を追加
    public static bool IsEmpty<T>(this IEnumerable<T> source)
        => !source.Any();

    // IEnumerable<T> を実装する型に ForEach を追加
    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        foreach (var item in source)
            action(item);
    }
}
int[] numbers = { 1, 2, 3, 4, 5 };
var list = new List<string> { "Alice", "Bob", "Carol" };
var empty = Array.Empty<int>();

Console.WriteLine(numbers.Sum2());    // 15
Console.WriteLine(empty.IsEmpty());   // True
Console.WriteLine(list.IsEmpty());    // False

list.ForEach(name => Console.WriteLine($"Hello, {name}!"));
// Hello, Alice!
// Hello, Bob!
// Hello, Carol!

int[] も List<string> も IEnumerable<T> を実装しているため、どちらでも同じ拡張メソッドが使えます。独自のインターフェースを定義してそこに拡張メソッドを追加すれば、そのインターフェースを実装するすべてのクラスに振る舞いを付け加えることができます。

public interface IPrintable
{
    string GetContent();
}

public static class PrintableExtensions
{
    // IPrintable を実装するすべての型に PrintToConsole を追加
    public static void PrintToConsole(this IPrintable source)
        => Console.WriteLine(source.GetContent());
}

public class Report : IPrintable
{
    public string Title { get; set; } = string.Empty;
    public string GetContent() => $"[Report] {Title}";
}

public class Invoice : IPrintable
{
    public int Number { get; set; }
    public string GetContent() => $"[Invoice] #{Number}";
}
var report  = new Report  { Title = "Q1 Summary" };
var invoice = new Invoice { Number = 42 };

report.PrintToConsole();  // [Report] Q1 Summary
invoice.PrintToConsole(); // [Invoice] #42

GetEnumerator の拡張メソッドサポート(C# 9.0)

C# 9.0 以降では、GetEnumerator を拡張メソッドとして定義することで、本来は foreach に対応していない型を foreach で列挙できるようになります。

foreach は、コンパイラが GetEnumerator() メソッドを探してループを展開します。このメソッドを拡張メソッドとして提供すれば、クラス自体を変更しなくても foreach が使えるようになります。

ここでは、通常は foreach で直接は回せない Range 型(1..5 のような範囲)を例にします。

// int の Range を foreach で使えるようにする拡張メソッド
public static class RangeExtensions
{
    public static IEnumerator<int> GetEnumerator(this Range range)
    {
        int start = range.Start.Value;
        int end   = range.End.Value;

        for (int i = start; i < end; i++)
            yield return i;
    }
}
// C# 9.0 以降: Range を foreach で列挙できる
foreach (int i in 1..6)
{
    Console.Write($"{i} "); // 1 2 3 4 5
}
Console.WriteLine();

同様に、ライブラリの既存クラスが IEnumerable を実装していない場合でも、GetEnumerator 拡張メソッドを追加するだけで foreach に対応させることができます。

// サードパーティのクラス(変更不可と想定)
public class NumberRange
{
    public int From { get; set; }
    public int To   { get; set; }
}

// 拡張メソッドで foreach サポートを追加
public static class NumberRangeExtensions
{
    public static IEnumerator<int> GetEnumerator(this NumberRange range)
    {
        for (int i = range.From; i <= range.To; i++)
            yield return i;
    }
}
var range = new NumberRange { From = 3, To = 7 };

foreach (int n in range)
{
    Console.Write($"{n} "); // 3 4 5 6 7
}
Console.WriteLine();

まとめ

トピック ポイント
拡張メソッドの定義 static class 内に static メソッドとして定義し、第 1 引数に this を付ける
呼び出し インスタンスメソッドと同じ記法で呼び出せる
インポート 定義された名前空間を using でインポートする必要がある
インターフェースへの拡張 第 1 引数をインターフェース型にすれば、実装クラスすべてに追加できる
GetEnumerator サポート GetEnumerator を拡張メソッドで定義すれば任意の型を foreach で使える

拡張メソッドはソースコードを変更できないクラスやインターフェースに機能を追加したいときに強力です。ただし、乱用するとどこにメソッドが定義されているかが分かりにくくなるため、意味がまとまった単位で static class を分けることが大切です。

C# .NET 拡張メソッド Extension Methods LINQ
← [C#] カスタム型変換(Custom Type Conversions)の使い方 — explicit と implicit を使いこなす [C#] 匿名型(Anonymous Types)の使い方 →

Related Posts

  • [C#] LINQ to Objects を理解する: クエリの内部表現 Jun 22, 2026
  • [C#] LINQ to Objects を理解する: ページング・集合演算・集計 Jun 21, 2026
  • [C#] LINQ to Objects を理解する: フィルター・射影・並べ替え Jun 20, 2026
  • [C#] LINQ to Objects を理解する: 基本構文と遅延実行 Jun 19, 2026

Table of Contents

  • 拡張メソッドの定義
  • 拡張メソッドの呼び出し
  • 拡張メソッドのインポート
  • 特定のインターフェースを実装した型への拡張
  • GetEnumerator の拡張メソッドサポート(C# 9.0)
  • まとめ

Recent Posts

  • [C#] プラグインで拡張できるアプリケーションを設計する Jul 9, 2026
  • [C#] 属性でコードに意味を与える Jul 8, 2026
  • [C#] 外部アセンブリを読み込み実行時に型を呼び出す Jul 7, 2026
  • [C#] リフレクションで型の中身を調べる Jul 6, 2026
  • [C#] 型メタデータとリフレクションの基礎を理解する Jul 5, 2026

Categories

  • C#120
  • .NET119
  • AWS27
  • Laravel16
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Diagnostics1
  • Filament1
  • Git1
  • SQS1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • コレクション
  • PHP
  • セキュリティ
  • MySQL
  • Linux
  • パフォーマンス
  • Apache
  • System.Collections.Generic
  • デリゲート
  • Code Snippet
  • DynamoDB
  • LINQ
  • NoSQL
  • PHP-FPM
  • RDS
  • System.Collections
  • Windows
  • メモリ管理
  • リフレクション
  • DoS
  • Nginx
  • WordPress
  • メタデータ
  • ラムダ式
  • 監視
  • 設計
  • Amazon Linux 2023
  • Delegate
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • LINQ to Objects
  • OPCache
  • Pointer
  • Reflection
  • System.Collections.Specialized
  • Unsafe
  • Webサーバー
  • インターフェース
  • オブジェクト指向
  • クラス設計
  • デザインパターン
  • パターンマッチング
  • ポインター
  • 継承
Powered by Hugo & Explore Theme.