developmentor - a developer services company				  
				      C# Tutorial
   Modules

Indexers


Goals:

  • Describe the concept of indexers.
  • Show the definition and invocation syntax for indexers.

Overview

An indexer provides a way for a class to support array-like indexing using the square brackets operator [ ]. This works well for any class that represents a collection of data keyed by index.


Motivation

Some classes can be thought of as a collection of other objects. A department at a company might contain all of the employees that work in that department. An investment portfolio would contain the current set of stocks owned. A polygon could store all the points that make up the shape. In each case, it might make sense to allow client code to access elements of the collection by giving a unique index. For example, an employee record might be requested from the department by specifying the employee's id number or name. A particular stock might be extracted from an investment portfolio by giving its ticker symbol. The points of a polygon might be indexed by an integer representing the order in which the points are connected.

Each collection class would need some private data structure behind the scenes in which to store the collection of data. The most common case would be a simple array but more sophisticated implementations are possible as well. To allow client code to access the elements of the collection, public access methods would likely be provided. The set access method would require two parameters: the index and the data. The get access method would take the index as an argument and return the corresponding value. An implementation for a simple polygon class is shown below.

Clients of the polygon class use the get and set methods for access to the collection of points.

The private data / public access methods pattern described above works reasonably well. The clients interact with the access methods while the data store is hidden behind the scenes. As an alternative, the class designer can supply an indexer instead of traditional get and set methods. The special indexer syntax allows the square bracket operator to be used for access instead of regular get and set methods calls. The primary advantage is that the indexer client code is more concise than analogous code using traditional access methods.


Basic indexer

Recall that there are typically three components to the implementation of any data access pattern: the get method, the set method, and the field used to store the information. Indexers provide a fancy way of writing the get and set access methods but do not give any help with data storage. Therefore, lurking behind the scenes of any indexer implementation will be some sort of data store, typically just a private field. The polygon example would likely use an array of points to store the data as shown below.

Indexers provide a special way to write get and set access methods that are invoked using the square brackets operator rather than traditional method call syntax. The indexer definition syntax is a bit obscure and fairly lengthy. First, the access level such as public or private is specified. Next comes the type of data being indexed; for example, our polygon sample would specify Point while the investment portfolio example would use Stock. After the type comes the keyword this; there is no option here, the keyword must be included in the definition of every indexer. Next, placed inside square brackets, comes the type and name of the index. Lastly comes the body of the indexer with the get and set access methods defined inside. The syntax is summarized in the figure below.

The get and set accessors are defined inside the body of the indexer. The definition of the accessors is simplified by the fact that much of the interface information is already captured in the indexer declaration. In particular, the indexer declaration contains the type of data being indexed and the type and name of the index itself.

Recall that a traditional set method for indexed data would take two arguments: the index and the data. The implementation of a set accessor does not specify these parameters explicitly; in fact, the method header is completely omitted and much of the parameter information is taken from the indexer declaration. The name of the index is determined by the name in the indexer declaration. The name of the data parameter is the special symbol value. The term value is imposed on the programmer by the C# language designers and cannot be changed. The example below shows the definition of the set accessor for the polygon example.

A traditional get method would take only the index as an argument and return the corresponding data. The implementation of the get accessor dispenses with this detail and specifies only the method body preceded by the keyword get. The get accessor must return an object of the type being indexed as expected for any get access method.

The client code that makes use of an indexer is clean and simple. The client applies the square brackets operator to an object of the class and the compiler invokes the appropriate accessor automatically. When the indexer is used on the left hand side of the assignment operator the set accessor is used. In all other cases the get accessor is invoked.


Index type

Most indexers have a simple integer index; however, the index can actually be of any type. The code below illustrates this by showing a department class that uses an indexer to allow employees to be accessed by name. The type of the index in this case is a string.


Index number

Indexers support multiple parameters. The indices are placed inside the square brackets and separated by commas. The code below shows a matrix class with an indexer that requires two parameters: the row and column.


Indexer overloading

A class may offer multiple indexers as long as each version has a unique set of indices. The example below shows a matrix class that offers two indexers. The first indexer allows the user to pass a single index, the row number, to access an entire row of data. The second indexer requires both a row and a column index and allows access to a single element of the matrix

This material is excerpted from the Programming C# course offered by DevelopMentor.