An indexer is a member that enables objects to be indexed in the same as an array.
If properties are ‘virtual fields‘, indexers are more like ‘virtual arrays‘. Indexers permit instances of a class or struct to be indexed in the same way as arrays. Indexers are similar to properties except that their accessors take parameters. They allow a class to emulate an array, where the elements of this array are actually dynamically generated by function calls.
An indexer is declared like a property except that the name of the member is this followed by a parameter list written between the delimeters [ and ]. The paramaters are available in the accessor(s) of the indexer. Similar to properties, indexers can be read-write, readonly, and write only and the accessor of an indexer can be virtual.
The following piece of code defines a class to hold a list of runners in an athletics race. The runners are held in lane order, and an indexer is exposed which allows the list to be both read from and written to. The indexer deals gracefully with cases in which the lane number passed to it is either too high or too low.
class RaceDetails
{
private string[] lanes;
public RaceDetails()
{
this.lanes = new strings[8];
}
public string this[int i]
{
get
{
return (i>=0 && i<8) ? this.lanes[i] : “error”;
}
set
{
if (i>=0 && i<8)
this.lanes[i] = value;
}}
}
The following simple code illustrates use being made of the class just defined. The name of the person in the race’s first lane is set, and then this name is sent to a console window.
RaceDetails rd = new RaceDetails();
rd[0] = “fred”;
Console.writeLine (“lane One :” + rd[0]) ;
As can be seen from the example, an indexer is defined in a similar way to a property. One important difference is in the indexer’s signature; the word ‘this’ is used in place of a and after this word indexing elements are provided.
~ Concept
Indexers aren’t differentiated by name, and a class cannot declare two indexers with the same signature. However, this does not entail that a class is limited to just one indexer. Different indexers can have different types and numbers of indexing elements (these being equivalent to method parameters, except that each indexer must have at least one indexing element, and the ‘ref and ‘out’ modifiers cannot be used).
Because indexing elements are not limited to integers, the original description of indexers as ‘virtual arrays’ actually rather undersells them. For example, where the indexing elements include strings, indexers present themselves more like hash tables.
The following code shows an implementation for the RaceDetails class of an indexer whose indexing element is a string. Using this indexer it is possible to refer to a lane using the name of the person currently filling that lane.
public string this[string s]
{
get
{
Int laneNum = getposition(s);
return (laneNum<0) ? “error” : this.lanes[laneNum];
}
set
{
int laneNum = getposition(s);
if (laneNum>=0) this.lanes[laneNum] = value;
}
}
private int getposition(string myName)
{
for (int x=0; x<lanes.Length; x++)
{
if (myName==lanes[x]) return x;
}
return -1;
}
The following piece of code gives an example of the kind of use one might make of this string indexer.
rd[“fred”] = “j ill”;
After the execution of this code, the name “fred” will be replace with name the “jill” in object array ‘rd’. The string indexer will return index number of “fred” where “jill” will be aced.
The following example shows how to declare a private array field, myArray, and an. sing the indexer’ allows direct access to the instance b [i] The alternative to using the indexer is to declare the array as a public member and access its membersmyArray [i] directly.
Indexer
using System;
class indexerclass
{
private int[] myArray = new int [100];
public int this [int index] //indexer declaration
{
get
{
// Check the index limits
if (index < 0 //dex >,:, = 100)
return 0;
else
return myArray [index];
}
set
{
if (! (index < 0 Ilindex > = 100)
myArray [index] = value;
}
}
}
public class Mainclass
{
public static void Main()
{
Indexerclass b = new IndexerClass();
// call the indexer to initialize the elements # 3 and # 5.
b[3] = 256;
b(5] = 1024;
for (int i = 0; i < 10; i++)
{
Console.writeLine (“element” {0} = {1}”, i, b[i]);
}
}
}
OUTPUT:
Element # 0 = 0
Element # 1 = 0
Element # 2 = 0
Element # 3 = 256
Element # 4 = 0
Element # 5 = 1024
Element # 6 = 0
Element # 7 = 0
Element # 8 = 0
Element # 9 = 0
Element # 10 = 0
Notice that when an indexer’s access in evaluated (for example in a Console.Writer statement) the get accessor is invoked. Therefore, if no get accessor exists a compile-time error occurs.
Comparison between Properties and Indexers
Indexers are similar to properties. Except for the difference shown in the following table, all of the rules defined for property accessors apply to indexer accessor as well.