C# Indexer

This keyword

An indexer provides array-like syntax. It allows a type to be accessed the same way as an array. Properties such as indexers often access a backing store. We often accept an int parameter and access a backing array.

Property

An indexer is a member that enables an object to be indexed in the same way as an array.

The C# Programming Language

Example

Note

This program contains a class that has an indexer member, which itself contains a get accessor and a set accessor. These accessors are implicitly used when you assign the class instance elements with array syntax.

Tip:An indexer provides a level of indirection where you can insert bounds-checking. This improves reliability and simplicity.

Program that uses indexer with int: C#

using System;

class Layout
{
    string[] _values = new string[100]; // Backing store

    public string this[int number]
    {
	get
	{
	    // This is invoked when accessing Layout instances with the [ ].
	    if (number >= 0 && number < _values.Length)
	    {
		// Bounds were in range, so return the stored value.
		return _values[number];
	    }
	    // Return an error string.
	    return "Error";
	}
	set
	{
	    // This is invoked when assigning to Layout instances with the [ ].
	    if (number >= 0 && number < _values.Length)
	    {
		// Assign to this element slot in the internal array.
		_values[number] = value;
	    }
	}
    }
}

class Program
{
    static void Main()
    {
	// Create new instance and assign elements
	// ... in the array through the indexer.
	Layout layout = new Layout();
	layout[1] = "Frank Gehry";
	layout[3] = "I. M. Pei";
	layout[10] = "Frank Lloyd Wright";
	layout[11] = "Apollodorus";
	layout[-1] = "Error";
	layout[1000] = "Error";

	// Read elements through the indexer.
	string value1 = layout[1];
	string value2 = layout[3];
	string value3 = layout[10];
	string value4 = layout[11];
	string value5 = layout[50];
	string value6 = layout[-1];

	// Write the results.
	Console.WriteLine(value1);
	Console.WriteLine(value2);
	Console.WriteLine(value3);
	Console.WriteLine(value4);
	Console.WriteLine(value5); // Is null
	Console.WriteLine(value6);
    }
}

Output

Frank Gehry
I. M. Pei
Frank Lloyd Wright
Apollodorus
(null)
Error
Squares

This program includes a Layout class with an indexer we define. The Layout class contains an indexer that has get and set method bodies. These accessors have logic that ensures the array will not will be accessed out-of-bounds.

Note:The array is termed the backing store for the indexer property in this example.

Array

In Main we assign elements in the Layout class backing store to various string literals. The elements -1 and 1000 are used as parameters to the indexer, but these will not result in the backing store being changed. They are not valid.

String Literal

However:No exceptions are thrown by the invalid parameters. The indexer logic prevents this.

Exception

Finally, the program displays the first four valid elements from the Layout class. It displays an element that was not changed from null. And then it shows the result of an invalid access.

Console.WriteLine

Parameters

Class shapes

The parameter list varies depending on your requirements. In a collection that maps string keys to values, you will want to have an indexer that accepts a string. This makes the class have a lookup function based on the indexer.

2D collections. If you are trying to simulate a 2D collection, you can use two parameters in the indexer. Because indexers are actually regular methods in the implementation, there are few limitations regarding the parameter types.

But:Ref and out parameters are not allowed. You will need a custom method to use these parameter modifiers.

RefOut

Framework

Framework: NET

Indexers have been used throughout the .NET Framework in Microsoft's own code since the Framework was released. Almost all of the iterative collections and searchable collections use indexers as an option to access elements.

Note:This includes the Dictionary collection, which allows you to look up elements with the indexer.

And:The indexer for the Dictionary often uses a string parameter as the indexer argument.

Dictionary

Also, ArrayList and List use indexers to simulate the built-in syntax of arrays in the C# language. This makes the List able to be used in syntactically the same way as an array when assigning or reading elements that are allocated.

HashtableArrayListList

Intermediate language

Abstract squares

We examine the intermediate language for the indexer shown above. You can see that a separate metadata table exists that stores the get_Item and set_Item methods, which implement the logic for the get and set accessors in the indexer.

In the .NET Framework, the metadata implements properties in the same way as methods but with an additional table to provide more information about the type of methods. There should be no performance drawback with an indexer.

Intermediate Language
Intermediate language for example indexer: IL

.property instance string Item
{
    .get instance string Layout::get_Item(int32)
    .set instance void Layout::set_Item(int32, string)
}

Interface indexer

Interface example: IPerl

This program uses an indexer member on an interface type. The interface declares the indexer and leaves the get and set accessors empty. The Implementation class then declares an indexer with the same parameters.

Tip:You can use the indexer through the interface type. This provides a separation of implementation from intent.

Program that implements indexer on interface: C#

using System;

interface IPerl
{
    int this[int number] { get; set; }
}

class Implementation : IPerl
{
    int[] _data = { 0, 10, 20, 30 }; // Default values
    public int this[int number]
    {
	get
	{
	    // Get accessor implementation.
	    return this._data[number];
	}
	set
	{
	    // Set accessor implementation.
	    this._data[number] = value;
	}
    }
}

class Program
{
    static void Main()
    {
	// Create an object instance.
	// ... Use the indexer through the interface type.
	IPerl perl = new Implementation();
	Console.WriteLine(perl[0]);
	Console.WriteLine(perl[1]);
	Console.WriteLine(perl[2]);
	Console.WriteLine(perl[3]);
	// Use set accessor.
	perl[0] = -1;
	Console.WriteLine(perl[0]);
    }
}

Output

0
10
20
30
-1
Main method

In this example, the IPerl type is an interface with one member of indexer type. The Implementation type implements IPerl and provides data for the indexer accessors. And the Program class contains the Main entry point.

Next, the IPerl interface requires that there be a public set accessor and get accessor. The C# specification contains detailed rules about when implementations can omit the set or get accessors.

The Implementation type is a class that implements the IPerl interface. It provides an indexer implementation. An indexer uses the member name "this". The square brackets with an arbitrary parameter list.

Tip:In a real program, the set and get accessors might provide more detailed logic for preventing or reporting failures.

And:The Main method uses the get and set accessors of the Implementation class instance through the IPerl interface.

Main, Args

Summary

C# programming language

An indexer is a property accessor type. Indexers have a somewhat more complicated syntax than other properties. They provide a function that is used when you do array-like accesses on the class instance.

Review:Indexers provide a level of indirection. There you can insert bounds-checking. This enhances the reliability of programs.


C#: Class