C#でプログラミングをしていると、配列やリストのように data[0] や list["key"] といった形式で、オブジェクト内部のデータにアクセスしたい場面が出てきます。
通常、自作クラスでこれを行おうとすると GetItem(0) や SetItem(0, value) のようなメソッドを用意する必要がありますが、C#にはもっとスマートな方法が用意されています。
それが 「インデクサ(Indexer)」 です。
これにより、コードの可読性が向上し、利用する側にとって直感的なクラス設計が可能になります。
この記事では、C#におけるインデクサの基本的な書き方から、文字列をキーにする方法、複数の引数を取る応用テクニックまで、豊富なサンプルコードを交えて解説します。
![]() 執筆者:マヒロ |
|
インデクサ(Indexer)とは?基本的な仕組み
インデクサは、クラスや構造体のインスタンスに対して、配列と同じように [](ブラケット)を使ってデータにアクセスできるようにする機能です。
「スマート配列」とも呼ばれることがあります。
インデクサの基本構文
インデクサはプロパティと非常によく似た構文で定義します。
最大の違いは、プロパティ名のかわりに this キーワードを使用し、引数(インデックス)を受け取る点です。
public 戻り値の型 this[インデックスの型 index]
{
get
{
// 値を返す処理
}
set
{
// 値を設定する処理(valueキーワードを使用)
}
}
プロパティと同様に get アクセサと set アクセサを持ちますが、インデクサは引数を取るため、メソッドのような側面も併せ持っています。
インデクサの実装方法とサンプルコード
それでは、実際にインデクサを使ったクラスを作成してみましょう。
ここでは、内部に文字列の配列を持ち、それを安全に操作できるシンプルなクラスを例に解説します。
基本的なインデクサの実装例
以下のコードは、最大10個の文字列を格納できる Sentence クラスです。
インデクサを使って、内部の配列にアクセスできるようにしています。
using System;
class Sentence
{
// 内部データを保持する配列
private string[] _words = new string[10];
// C# 8.0以降の ^演算子 (Index) などに対応するため、Lengthプロパティを用意するのが推奨
public int Length => _words.Length;
// インデクサの定義
public string this[int index]
{
get
{
// 範囲外アクセスのチェック
if (index < 0 || index >= _words.Length)
{
// 実務では標準的な配列と同様に例外を投げるのが一般的です
throw new IndexOutOfRangeException("インデックスが範囲外です。");
}
return _words[index];
}
set
{
if (index < 0 || index >= _words.Length)
{
throw new IndexOutOfRangeException("インデックスが範囲外です。");
}
_words[index] = value;
}
}
}
class Program
{
static void Main()
{
Sentence mySentence = new Sentence();
// インデクサを使って値をセット(配列のように扱える)
mySentence[0] = "C#";
mySentence[1] = "は";
mySentence[2] = "楽しい";
// インデクサを使って値を取得
Console.WriteLine($"{mySentence[0]} {mySentence[1]} {mySentence[2]}");
// Lengthプロパティがあるため、末尾からのアクセス(^1)も可能になります(C# 8.0以降)
// Console.WriteLine(mySentence[^8]); // "楽しい" と同じ意味になります
}
}
実行結果
C# は 楽しい
このコードでは、this[int index] という形でインデクサを定義しています。
get アクセサでは、渡された index を使って内部配列 _words の値を返しています。
実務での利用を想定し、範囲外のインデックスが渡された場合は IndexOutOfRangeException を投げるように実装しています。
また、Length プロパティ(または Count)を定義しておくことで、C# 8.0以降で導入された ^ 演算子(末尾からのインデックス指定)などが利用可能になり、より配列に近い操作感が実現できます。
応用編!文字列キーや複数引数での実装
インデクサの強力な点は、インデックスが必ずしも「整数(int)」である必要がないことです。
文字列やその他の型をインデックスとして使ったり、複数の引数を渡して多次元配列のように振る舞わせたりすることも可能です。
文字列をインデックス(キー)にする方法
Dictionary クラスのように、文字列をキーにして値を検索するインデクサを作ってみましょう。
using System;
using System.Collections.Generic;
class NicknameList
{
// 内部でDictionaryを持つ
private Dictionary<string, string> _names = new Dictionary<string, string>();
// 文字列をキーにするインデクサ
public string this[string key]
{
get
{
// キーが存在すれば値を返し、なければ "Unknown" を返す
return _names.ContainsKey(key) ? _names[key] : "Unknown";
}
set
{
_names[key] = value;
}
}
}
class Program
{
static void Main()
{
var list = new NicknameList();
// 文字列を使ってアクセス
list["Tanaka"] = "たなっしー";
list["Suzuki"] = "スーさん";
Console.WriteLine(list["Tanaka"]); // たなっしー
Console.WriteLine(list["Sato"]); // Unknown
}
}
ここでは this[string key] と定義することで、文字列をインデックスとして受け取っています。
この例では簡便さのためにキーが存在しない場合に "Unknown" を返していますが、標準の Dictionary はキーがないと例外を投げます。
実務でより厳密な動作が必要な場合は、例外を投げるようにするか、TryGetValue メソッドのような安全に取得する手段を別途用意するのが一般的です。
複数の引数を取るインデクサ(多次元対応)
インデクサは引数をカンマ区切りで複数指定することができます。
これを利用すると、Excelのセルや盤面のような「行と列」を持つデータを表現できます。
class GridMap
{
private int[,] _grid = new int[5, 5];
// 2つの引数を取るインデクサ
public int this[int x, int y]
{
get { return _grid[x, y]; }
set { _grid[x, y] = value; }
}
}
// 使用例
// var map = new GridMap();
// map[2, 3] = 10;
// Console.WriteLine(map[2, 3]);
インデクサのオーバーロード
メソッドと同じように、インデクサもオーバーロード(多重定義)が可能です。
引数の型や数が異なれば、一つのクラスに複数のインデクサを定義することができます。
class FlexibleList
{
private string[] _items = { "Apple", "Banana", "Cherry" };
// 1. int型でアクセスするインデクサ
public string this[int index]
{
get => _items[index]; // 式形式のメンバー定義(=>)も使用可能
}
// 2. string型で検索するインデクサ(オーバーロード)
public int this[string name]
{
get => Array.IndexOf(_items, name);
}
}
class Program
{
static void Main()
{
var list = new FlexibleList();
// 整数で要素を取得
Console.WriteLine(list[1]); // Banana
// 文字列でインデックス番号を取得
Console.WriteLine(list["Cherry"]); // 2
}
}
この例では、int を受け取って string を返すインデクサと、string を受け取って int(インデックス番号)を返すインデクサの2つを定義しています。
引数の型によって、コンパイラが自動的にどちらのインデクサを使うかを判断してくれます。
インデクサとプロパティの違い
インデクサは「引数付きプロパティ」とも呼ばれますが、通常のプロパティとはいくつかの明確な違いがあります。
| 項目 | プロパティ | インデクサ |
|---|---|---|
| 名前 | 任意の名前を付ける | 名前はない(this キーワードを使用) |
| 引数 | 持てない | 必ず1つ以上持つ |
| static | staticにできる | staticにできない(インスタンス固有) |
| 呼び出し | obj.Name |
obj[index] |
特に重要なのは、インデクサはstatic(静的)メンバーにできないという点です。
インデクサは常にインスタンス(オブジェクト)に対してアクセスするものです。
インターフェースでのインデクサの定義
インターフェースにインデクサを含めることも可能です。
これにより、クラスに対して「配列のようなアクセス機能」を持つことを強制できます。
public interface IStringContainer
{
// インデクサの定義(get/setの有無を指定)
string this[int index] { get; set; }
}
public class MyContainer : IStringContainer
{
private string[] _data = new string[10];
// インターフェースの実装
public string this[int index]
{
get => _data[index];
set => _data[index] = value;
}
}
インターフェースでは実装を持たず、{ get; set; } のようにアクセサの有無だけを定義します。
C#のスキルを活かして年収を上げる方法
以上、C#のインデクサさについて詳しく解説してきました。
なお、C#のスキルがある場合には、「転職して年収をアップさせる」「副業で稼ぐ」といった方法を検討するのがおすすめです。
業務システム開発やアプリ開発、ゲーム開発において需要の高いC#を扱えるエンジニアは、転職によって数十万円の年収アップはザラで、100万円以上年収が上がることも珍しくありません。
なお、転職によって年収を上げたい場合は、エンジニア専門の転職エージェントサービスを利用するのが最適です。
併せて、副業案件を獲得できるエージェントにも登録しておくと、空いている時間を活かして稼げるようなC#の案件を探しやすくなります。
転職エージェントも副業エージェントも、登録・利用は完全無料なので、どんな求人や副業案件があるのか気になる方は、気軽に利用してみるとよいでしょう。



