インデクサ

出典: フリー百科事典『ウィキペディア(Wikipedia)』
Jump to navigation Jump to search

プログラミング言語におけるインデクサ: indexer) は、クラス構造体インスタンス配列と同様の添字を指定してアクセスするための構文である。

概要[編集]

言語仕様に配列を持つプログラミング言語の多くは配列要素にアクセスするための添字による特殊な構文を持つ。その一方で、オブジェクトは配列ではないが、例えばリストや辞書などのように、オブジェクトそのものをコレクションとして扱いたい場合がある。

インデクサがない言語では通常getterやsetterと呼ばれる要素アクセスのためのメソッドを実装したり、内部の配列をプロパティとして公開するなどしてアクセスするのが一般的であるが、以下の問題点がある。

  • コードの冗長化による可読性の低下
  • 言語によってはgetやsetが識別子として扱われている場合があり、アクセサメソッドの名前が冗長化しやすい
  • getterメソッドの戻り値を使用しないような無駄なメソッド呼び出しが許容されてしまう
  • 内部配列を公開するようなパターンはそもそも避けるべきである

インデクサを用いることでオブジェクト内の列挙要素へのアクセスを配列へのアクセスと同様に記述できる他、メソッド呼び出しと異なりインデクサへのアクセスはプロパティのそれと同様に扱われる。そのため、開発環境のサポートが受けられる場合において、配列要素にアクセスはするが戻り値の処理を記述し忘れる、などのコードは構文レベルでのエラーとなりコーディングミスを認識しやすくなる。

ただし、インデクサは実質的にはgetter/setterメソッド呼び出しの糖衣構文であり、インデクサそのものは当然ながら反復子としての機能は持たない。インデクサを記述したからといって配列のようにforeachなどの反復構文がそのまま使えるわけではない他、メソッド呼び出しのオーバーヘッド減少などの効果も特にない(コンパイラによるインライン展開等は当然受ける)

プログラミング言語C#のインデクサはC++の添え字演算子の多重定義と似ているが次のような点で発展したものだと見ることもできる。ただしC++とC#の言語設計上の事情も絡んでいるので、単純に比較できるものではない。

  • インデクサではプロパティのように値を得るときと代入するときとで実際には別のメソッドに分かれている。
  • インデクサは単独で多次元な配列を模倣できる。C++で同じようなことをするには間に一時的にオブジェクトを入れるなどの技巧を凝らす必要がある。

他の言語ではC#のインデクサに似た機能として、Visual Basic .NETの引数付きプロパティやC++/CLIのインデックス付きプロパティなどが存在する。

リストを表すコレクションの要素のアクセスでは、インデクサを用いない言語では例えば次のようなインターフェイスメソッドによって定義される。

1) index番目の要素の取り出し

Object get(int index);
例:Object o = list.get(3);

2) index番目の要素に Object o をセット

void set(int index, Object o);
例:list.set(2, o);

C# のインデクサではリストの要素へのアクセスを配列のアクセスと同じように記述することができる。

 object o = list[3];
 list[2] = o;

この際インデックスとして整数以外の値(文字列やオブジェクトなど)も使用することができ、ハッシュテーブルなどの連想配列を表すコレクションに使用されている。

 object o = map["key"];

[編集]

C#[編集]

C#においては、クラスおよび構造体の内部にインデクサを持つことができる。

インデクサはthis[添え字リスト]の形式で宣言する。

インデクサの構文内ではgetsetが、 setアクセサ内では、valueがそれぞれ文脈キーワードとして機能する。

  class TwoByTwoMatrix {

      private int[][] items = new[]{
          new[] { 1, 2 },
          new[] { 3, 4 }
      };

      // セルの値を取得、設定するインデクサ
      public int this[int index0, int index1] {
          get { return items[index0][index1]; }
          set { items[index0][index1] = value; }
      }

  }

呼び出し側では、配列にアクセスするような構文でインデクサの機能を呼び出す。

  var matrix = new TwoByTwoMatrix();
  // setアクセス
  matrix[0, 0] = 10;
  // getアクセス
  int num = matrix[0, 1]
  // get ⇒ 加算 ⇒ set
  matrix[1, 0] += 10;

通常のメソッドと異なり代入を行わないインデクサメソッドの呼び出しは行えない。下記のような呼び出しは構文エラーとなる他、戻り値void型のインデクサを定義することもできない。ただし、インデクサを介して呼び出したオブジェクトのメンバを呼び出すような場合は構文上問題ない。

 // 構文エラーとして扱われる
  matrix[1, 0];
  
 // 次の呼び出しは問題ない(意味はないが)
  matrix[1, 0].ToString();

他言語との相互運用[編集]

他言語との相互運用のため、既定ではItemという名前のインデックス付きプロパティが自動生成される。

System.Runtime.CompilerServices.IndexerNameAttribute属性を付加することで、自動生成されるインデクサの名前を明示的に指定できる。 この機能が利用されている代表的な例として、System.Stringクラスが挙げられる。System.Stringクラスではインデクサの名前はCharsとなるように指定されている。 [1]

スニペット[編集]

Visual Studio IDE や Visual Studio Code では、以下のようなコードスニペットが用意されている。

  • indexer : get,setアクセサを持つ標準的なインデクサ

Visual Basic (.NET)[編集]

Visual Basic においては、Defaultキーワード付きのインデックス付きプロパティがインデクサとしてアクセス可能となる。

Public Class StringArray
    Private m_Item As String() = New String(10) {}
    ' Defaultが宣言されたインデックス付きプロパティはインデクサとしてアクセス可能
    Default Public Property Item(index As Integer) As String
        Get
            Return m_Item(index)
        End Get
        Set(ByVal value As String)
            m_Item(index) = value
        End Set
    End Property
End Class
  Dim obj As StringArray = New StringArray
  ' getアクセス
  Dim str As String = obj(1)
  ' setアクセス
  obj(2) = str

脚注[編集]

[ヘルプ]

関連項目[編集]