C# で利用できる基本型の1つに配列があります。
配列では i 番目の要素を読み書きする際、
a[i] というように [] を用います。
「演算子のオーバーロード」
でも述べましたが、
ユーザー定義型の理想は、組込み型とまったく同じように扱えることです。
そこで、C# では、
ユーザー定義型が配列型と同様に [] を用いた要素の読み書きが行えるようにインデクサという仕組みが用意されています。
インデクサを定義することで、ユーザー定義型のオブジェクトでも、
配列と同じような a[i] という形での要素の読み書きができるようになります。
インデクサは以下のようにして定義します。
アクセスレベル 戻り値の型 this[添字の型 添字] { set { // setアクセサ // ここに値の変更時の処理を書く。 // value という名前の変数に代入された値が格納される。 // 添字が使える以外はプロパティと同じ。 } get { // getアクセサ // ここに値の取得時の処理を書く。 // メソッドの場合と同様に、値はreturnキーワードを用いて返す。 // こっちも添字が使える以外はプロパティと同じ。 } }
インデクサの定義の仕方はプロパティの定義の仕方に似ています。
プロパティ名の代わりに this[] を使うことと、
添字が使えること以外はプロパティと同じです。
例えば、以下のように添字の下限と上限の両方を指定できる配列を作ることが出来ます。
using System; /// <summary> /// 添字の下限と上限を指定できる配列。 /// </summary> class BoundArray { int[] array; int lower; // 配列添字の下限 public BoundArray(int lower, int upper) { this.lower = lower; array = new int[upper - lower + 1]; } public int this[int i] { set{this.array[i - lower] = value;} get{return this.array[i - lower];} } } class IndexerSample { static void Main() { BoundArray a = new BoundArray(1, 9); for(int i=1; i<=9; ++i) a[i] = i; for(int i=1; i<=9; ++i) Console.Write("a[{0}] = {1}\n", i, a[i]); } }
a[1] = 1 a[2] = 2 a[3] = 3 a[4] = 4 a[5] = 5 a[6] = 6 a[7] = 7 a[8] = 8 a[9] = 9
インデクサの添字は1つである必要はなく、 複数の添字を利用することが出来ます。
using System; /// <summary> /// jugged array を使った行列。 /// rectangular array のように[i, j]という添字で要素の読み書き可能。 /// </summary> class Matrix { int[][] array; public Matrix(int rows, int cols) { this.array = new int[rows][]; for(int i=0; i<rows; ++i) this.array[i] = new int[cols]; } public int this[int i, int j] { set{this.array[i][j] = value;} get{return this.array[i][j];} } } class IndexerSample { static void Main() { Matrix a = new Matrix(4, 4); for(int i=0; i<4; ++i) for(int j=0; j<4; ++j) a[i, j] = (i+1) * (j+3); for(int i=0; i<4; ++i) { for(int j=0; j<4; ++j) Console.Write("{0,4}", a[i, j]); Console.Write("\n"); } } }
3 4 5 6 6 8 10 12 9 12 15 18 12 16 20 24
また、添字の型は整数型である必要はありません。
例えば、以下のように添字が string 型のインデクサを持つ辞書クラスを作ることも出来ます。
using System; /// <summary> /// Dictionary クラスの項目。 /// </summary> internal class Item { public string key; public string value; public Item next; public Item(string key, string value, Item next) { this.key = key; this.value = value; this.next = next; } } /// <summary> /// 辞書クラス。 /// </summary> class Dictionary { Item head; public Dictionary() { this.head = new Item(null, null, null); } public string this[string key] { set { for(Item item = this.head.next; item != null; item =item.next) if(item.key == key) { item.value = value; return; } this.head.next = new Item(key, value, this.head.next); } get { for(Item item = this.head.next; item != null; item =item.next) if(item.key == key) return item.value; return null; } } } class IndexerSample { static void Main() { Dictionary dic = new Dictionary(); dic["ハァ"] = "( ゚Д゚)?"; dic["ハァハァ"] = "(;´Д`)"; dic["ポカーン"] = "( ゚д゚)"; dic["オマエモナ"] = "(´∀`)"; Console.Write(dic["ハァハァ"]); } }
(;´Д`)
Ver. 2.0
C# 2.0 では、 プロパティと同様に、 インデクサの set/get アクセサそれぞれ異なるアクセスレベルを設定できるようになりました。