News & UpdatesProgrammingWeb programming StoreMy Projects
Links
Affiliates

C# Tutorial – 17 – Indexers

Indexers allow an object to be treated as an array. They are declared in the same way as properties, except that the this keyword is used instead of a name and their accessors take parameters. In the example below, the indexer corresponds to an object array called data, so the type of the indexer is set to object.

class MyArray
{
  object[] data = new object[10];
 
  public object this[int i]
  {
    get { return data[i]; }
    set { data[i] = value; }
  }
}

The get accessor returns the specified element from the object array, and the set accessor inserts the value into the specified element. With the indexer in place an instance of this class can be created and used as an array, both to get and set the elements.

static void Main() 
{
  MyArray a = new MyArray();
  a[5] = "Hello World";
  object o = a[5]; // Hello World
}

Indexer parameters

The parameter list of an indexer is similar to that of a method, except that it must have at least one parameter and that the ref or out modifiers are not allowed. For example, if there is a two-dimensional array, the column and row indexes can be passed as separate parameters.

class MyArray
{
  object[,] data = new object[10,10];
 
  public object this[int i, int j]
  {
    get { return data[i,j]; }
    set { data[i,j] = value; }
  }
}

The index parameter does not have to be of an integer type. An object can just as well be passed as the index parameter. The get accessor can then be used to return the index position where the passed object is located.

class MyArray
{
  object[] data = new object[10];
 
  public int this[object o]
  {
    get { return System.Array.IndexOf(data, o); }
  }
}

Indexer overloading

Both of these functionalities can be provided by overloading the indexer. The type and number of arguments will then determine which indexer gets called.

class MyArray
{
  object[] data = new object[10];
 
  public int this[object o]
  {
    get { return System.Array.IndexOf(data, o); }
  }
 
  public object this[int i]
  {
    get { return data[i]; }
    set { data[i] = value; }
  }
}

Keep in mind that in a real program a range check should be included in the accessors, so as to avoid exceptions caused by trying to go beyond the length of the array.

public object this[int i]
{
  get { return (i >= 0 && i < data.Length) ? data[i] : null; }
  set { if (i >= 0 && i < data.Length) data[i] = value; }
}