bucket-sort logo bucket-sort

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

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] インデクサー [] (Indexer Methods)の使い方 — 文字列キー・オーバーロード・多次元・インターフェース定義まで

[C#] インデクサー [] (Indexer Methods)の使い方 — 文字列キー・オーバーロード・多次元・インターフェース定義まで

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

配列やリストは arr[0] のように [] でアクセスできますが、自作クラスでも同じ記法を使えると便利なことがあります。C# の インデクサー(Indexer) は、そのための仕組みです。

var container = new WordBook();
container["apple"] = "リンゴ";
Console.WriteLine(container["apple"]); // リンゴ

この記事では次の 4 つのトピックに沿って、インデクサーの使い方を解説します。

  1. 文字列キーによるインデックスアクセス
  2. インデクサーメソッドのオーバーロード
  3. 多次元インデックス
  4. インターフェース型でのインデクサー定義

インデクサーの基本構文

インデクサーは this[...] というキーワードで定義します。プロパティと同様に get / set アクセサーを持てます。

class MyList
{
    private string[] _data = new string[10];

    // インデクサーの定義
    public string this[int index]
    {
        get => _data[index];
        set => _data[index] = value;
    }
}
var list = new MyList();
list[0] = "Hello";
Console.WriteLine(list[0]); // Hello

通常のメソッドと違い、呼び出し側から見れば配列と同じ [] 記法 で値の読み書きができます。

1. 文字列キーによるインデックスアクセス

インデクサーのパラメーターは int に限りません。string をキーに使うことで、辞書(Dictionary)のような読み書きを自作クラスに持たせられます。

using System.Collections.Generic;

class WordBook
{
    private readonly Dictionary<string, string> _store = new();

    // string キーで読み書きするインデクサー
    public string this[string word]
    {
        get
        {
            if (_store.TryGetValue(word, out var meaning))
                return meaning;
            return $"('{word}' は未登録です)";
        }
        set => _store[word] = value;
    }

    public int Count => _store.Count;
}
var book = new WordBook();
book["apple"]  = "リンゴ";
book["banana"] = "バナナ";
book["cherry"] = "さくらんぼ";

Console.WriteLine(book["apple"]);   // リンゴ
Console.WriteLine(book["grape"]);   // ('grape' は未登録です)
Console.WriteLine(book.Count);      // 3

Dictionary<TKey, TValue> 自体もインデクサーで実装されているため、ラッパークラスとして追加ロジックを差し込みたいときにこのパターンが役立ちます。

2. インデクサーメソッドのオーバーロード

同一クラスにパラメーターの型や数が異なる複数のインデクサーを定義できます。これをインデクサーのオーバーロードといいます。

class DataStore
{
    private readonly string[] _array = new string[100];
    private readonly Dictionary<string, string> _map = new();

    // int インデックスでアクセス
    public string this[int index]
    {
        get => _array[index];
        set => _array[index] = value;
    }

    // string キーでアクセス
    public string this[string key]
    {
        get => _map.TryGetValue(key, out var v) ? v : string.Empty;
        set => _map[key] = value;
    }

    // int + string の組み合わせでアクセス(後述の多次元と組み合わせた例)
    public string this[int index, string suffix]
    {
        get => $"{_array[index]}-{suffix}";
    }
}
var store = new DataStore();

// int インデクサー
store[0] = "zero";
Console.WriteLine(store[0]);                   // zero

// string インデクサー
store["name"] = "Alice";
Console.WriteLine(store["name"]);              // Alice

// int + string インデクサー(getter のみ)
Console.WriteLine(store[0, "tag"]);            // zero-tag

オーバーロードを活用すると、同一の [] 構文でさまざまな検索軸に対応できます。ただし増やしすぎると可読性が落ちるため、設計に応じて使い分けてください。

3. 多次元インデックス

パラメーターを複数個にすれば、2 次元・3 次元の行列や表形式データを自然に表現できます。

class Matrix
{
    private readonly int[,] _data;
    public int Rows { get; }
    public int Cols { get; }

    public Matrix(int rows, int cols)
    {
        Rows = rows;
        Cols = cols;
        _data = new int[rows, cols];
    }

    // 2 次元インデクサー
    public int this[int row, int col]
    {
        get
        {
            if (row < 0 || row >= Rows || col < 0 || col >= Cols)
                throw new IndexOutOfRangeException($"インデックスが範囲外です: [{row}, {col}]");
            return _data[row, col];
        }
        set
        {
            if (row < 0 || row >= Rows || col < 0 || col >= Cols)
                throw new IndexOutOfRangeException($"インデックスが範囲外です: [{row}, {col}]");
            _data[row, col] = value;
        }
    }
}
var m = new Matrix(3, 3);

// 値の書き込み
m[0, 0] = 1; m[0, 1] = 2; m[0, 2] = 3;
m[1, 0] = 4; m[1, 1] = 5; m[1, 2] = 6;
m[2, 0] = 7; m[2, 1] = 8; m[2, 2] = 9;

// 値の読み取り
for (int r = 0; r < m.Rows; r++)
{
    for (int c = 0; c < m.Cols; c++)
        Console.Write($"{m[r, c],3}");
    Console.WriteLine();
}
// 出力:
//   1  2  3
//   4  5  6
//   7  8  9

多次元インデクサーは C# の組み込み多次元配列(int[,])と同じ [row, col] 記法になるため、利用者が直感的に使えます。

4. インターフェース型でのインデクサー定義

インデクサーはインターフェースにも定義できます。実装クラスに対してインデクサーの シグネチャ(型・アクセサー) を強制できるため、依存性の注入(DI)や単体テストの差し替えに役立ちます。

インターフェースの定義

public interface IStringContainer
{
    // int インデックスで string を読み書きできることを要求
    string this[int index] { get; set; }
}

{ get; set; } の代わりに { get; } だけにすれば読み取り専用インデクサーも定義できます。

インターフェースを実装するクラス

public class SomeClass : IStringContainer
{
    private readonly List<string> _items = new();

    // IStringContainer のインデクサーを実装
    public string this[int index]
    {
        get
        {
            if (index < 0 || index >= _items.Count)
                throw new ArgumentOutOfRangeException(nameof(index));
            return _items[index];
        }
        set
        {
            // 必要に応じてリストを拡張
            while (_items.Count <= index)
                _items.Add(string.Empty);
            _items[index] = value;
        }
    }

    public void Add(string item) => _items.Add(item);
    public int Count => _items.Count;
}

別の実装クラス(テスト用スタブなど)

public class StubStringContainer : IStringContainer
{
    private readonly Dictionary<int, string> _store = new();

    public string this[int index]
    {
        get => _store.TryGetValue(index, out var v) ? v : string.Empty;
        set => _store[index] = value;
    }
}

利用例

static void PrintAll(IStringContainer container, int count)
{
    for (int i = 0; i < count; i++)
        Console.WriteLine($"[{i}] = {container[i]}");
}

// 本番クラスで使う
var real = new SomeClass();
real.Add("Alice");
real.Add("Bob");
real.Add("Carol");
PrintAll(real, real.Count);
// [0] = Alice
// [1] = Bob
// [2] = Carol

// スタブで差し替える
var stub = new StubStringContainer();
stub[0] = "Stub-A";
stub[1] = "Stub-B";
PrintAll(stub, 2);
// [0] = Stub-A
// [1] = Stub-B

PrintAll メソッドは IStringContainer に依存しているため、実装クラスを差し替えても変更不要です。

読み取り専用インデクサー

C# 8.0 以降では readonly 修飾子をインデクサーの get アクセサーに付けられます。また、init アクセサー(C# 9.0)を使えばオブジェクト初期化子({ } 構文)での一度限りの書き込みも可能です。

class ReadOnlyGrid
{
    private readonly int[,] _data = { { 1, 2 }, { 3, 4 } };

    // 読み取り専用インデクサー
    public int this[int r, int c] => _data[r, c];
}

まとめ

トピック ポイント
基本構文 public T this[型 param] { get; set; } で定義
文字列キー string をパラメーターにすれば辞書風アクセスが可能
オーバーロード パラメーターの型・数が違えば複数定義できる
多次元 this[int r, int c] のようにパラメーターを増やすだけ
インターフェース string this[int index] { get; set; } と宣言し実装クラスに強制

インデクサーを使いこなすと、自作コレクションや設定クラスが 組み込み配列・辞書と同じ直感的な記法 で扱えるようになります。インターフェースとの組み合わせで依存性の逆転(DIP)も実現しやすくなるので、ぜひ積極的に活用してください。

C# .NET インデクサー Indexer インターフェース Interface
← [C#] ジェネリックの型制約(Constraining Type Parameters)入門 — where T : struct / class / new() / 基底クラス / インターフェース [C#] 演算子オーバーロード(Operator Overloading)の使い方 — 二項演算子・単項演算子・等価演算子・比較演算子 →

Related Posts

  • [C#] インターフェースの活用パターン — 参照取得・パラメータ・配列・既定実装・階層設計 May 6, 2026
  • [C#] インターフェース(Interface)を体系的に理解する May 5, 2026
  • [C#] 多重継承を許さない言語設計 — Diamond Problem と C++ の経験から考える Apr 25, 2026
  • [C#] プラグインで拡張できるアプリケーションを設計する Jul 9, 2026

Table of Contents

  • インデクサーの基本構文
  • 1. 文字列キーによるインデックスアクセス
  • 2. インデクサーメソッドのオーバーロード
  • 3. 多次元インデックス
  • 4. インターフェース型でのインデクサー定義
    • インターフェースの定義
    • インターフェースを実装するクラス
    • 別の実装クラス(テスト用スタブなど)
    • 利用例
  • 読み取り専用インデクサー
  • まとめ

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.