C# - Indexers



An indexer allows an object to be indexed such as an array. When you define an indexer for a class, this class behaves similar to a virtual array. You can then access the instance of this class using the array access operator ([ ]).

Syntax

Following is the sytnax of the one-dimensional indexer −

element-type this[int index] {
   // The get accessor.
   get {
      // return the value specified by index
   }
   
   // The set accessor.
   set {
      // set the value specified by index
   }
}

Use of Indexers

Declaration of behaviour of an indexer is to some extent similar to a property. similar to the properties, you use get and set accessors for defining an indexer. However, properties return or set a specific data member, whereas indexers returns or sets a particular value from the object instance. In other words, it breaks the instance data into smaller parts and indexes each part, gets or sets each part.

Defining a property involves providing a property name. Indexers are not defined with names, but with the this keyword, which refers to the object instance.

Example

Here, in this example, we demonstrate indexers, allowing objects of the IndexedNames class to be accessed like an array for storing and retrieving names −

using System
namespace IndexerApplication {
   class IndexedNames {
      private string[] namelist = new string[size];
      static public int size = 10;
      
      public IndexedNames() {
         for (int i = 0; i < size; i++)
         namelist[i] = "N. A.";
      }
      public string this[int index] {
         get {
            string tmp;
         
            if( index >= 0 && index <= size-1 ) {
               tmp = namelist[index];
            } else {
               tmp = "";
            }
            
            return ( tmp );
         }
         set {
            if( index >= 0 && index <= size-1 ) {
               namelist[index] = value;
            }
         }
      }
      static void Main(string[] args) {
         IndexedNames names = new IndexedNames();
         names[0] = "Zara";
         names[1] = "Riz";
         names[2] = "Nuha";
         names[3] = "Asif";
         names[4] = "Davinder";
         names[5] = "Sunil";
         names[6] = "Rubic";
         
         for ( int i = 0; i < IndexedNames.size; i++ ) {
            Console.WriteLine(names[i]);
         }
         Console.ReadKey();
      }
   }
}

When the above code is compiled and executed, it produces the following result −

Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.

Defining an Indexer

You can define an indexer by using the "this" keyword followed by a parameter list inside square brackets. Please note that - the indexer must include both get and/or set accessors to retrieve or assign values.

Example

In the following example, we define an indexer to store and retrieve integer values in an internal array using array syntax −

using System;
class SampleCollection
{
    private int[] arr = new int[5];

    public int this[int index]
    {
        get { return arr[index]; }
        set { arr[index] = value; }
    }
}

class Program
{
    static void Main()
    {
        SampleCollection sc = new SampleCollection();
        sc[0] = 10;
        sc[1] = 20;

        Console.WriteLine("Value at index 0: " + sc[0]);
        Console.WriteLine("Value at index 1: " + sc[1]);
    }
}

When the above code is compiled and executed, it produces the following result −

Value at index 0: 10
Value at index 1: 20

Indexer with String Key (Dictionary-style)

You can define indexers just like dictionaries where strings can be used as keys. This type of definition is useful when you want to retrieve or assign values using a string identifier.

Example

In the following example, we use a string indexer to access and store values in a dictionary-like structure −

using System;
using System.Collections.Generic;

class Contacts
{
    private Dictionary<string, string> phoneBook = new Dictionary<string, string>();

    public string this[string name]
    {
        get { return phoneBook.ContainsKey(name) ? phoneBook[name] : "Not Found"; }
        set { phoneBook[name] = value; }
    }
}

class Program
{
    static void Main()
    {
        Contacts c = new Contacts();
        c["Aman"] = "1234567890";
        c["Ravi"] = "9876543210";

        Console.WriteLine("Aman's Number: " + c["Aman"]);
        Console.WriteLine("Ravi's Number: " + c["Ravi"]);
        Console.WriteLine("Unknown: " + c["Unknown"]);
    }
}

When the above code is compiled and executed, it produces the following result −

Aman's Number: 1234567890
Ravi's Number: 9876543210
Unknown: Not Found

Indexers with Access Modifiers

You can also specify different access levels for the get and set accessors of an indexer using access modifiers.

Example

In the following example, the set accessor is private, so the indexer value can only be set within the class −

using System;

class MyCollection
{
    private string[] items = new string[3] { "One", "Two", "Three" };

    public string this[int index]
    {
        get { return items[index]; }
        private set { items[index] = value; }
    }

    public void UpdateItem(int index, string newValue)
    {
        this[index] = newValue;
    }
}

class Program
{
    static void Main()
    {
        MyCollection col = new MyCollection();

        Console.WriteLine("Before: " + col[1]);
        col.UpdateItem(1, "Updated");
        Console.WriteLine("After: " + col[1]);
    }
}

When the above code is compiled and executed, it produces the following result −

Before: Two
After: Updated

Overloaded Indexers

Indexers can be overloaded. Indexers can also be declared with multiple parameters and each parameter may be a different type. It is not necessary that the indexes have to be integers. C# allows indexes to be of other types, for example, a string.

Example

This is another example of the indexer. Here, we demonstrate overloaded indexers −

using System;
namespace IndexerApplication {
   class IndexedNames {
      private string[] namelist = new string[size];
      static public int size = 10;
      
      public IndexedNames() {
         for (int i = 0; i < size; i++) {
            namelist[i] = "N. A.";
         }
      }
      public string this[int index] {
         get {
            string tmp;
            
            if( index >= 0 && index <= size-1 ) {
               tmp = namelist[index];
            } else {
               tmp = "";
            }
            
            return ( tmp );
         }
         set {
            if( index >= 0 && index <= size-1 ) {
               namelist[index] = value;
            }
         }
      }
      
      public int this[string name] {
         get {
            int index = 0;
            
            while(index < size) {
               if (namelist[index] == name) {
                return index;
               }
               index++;
            }
            return index;
         }
      }

      static void Main(string[] args) {
         IndexedNames names = new IndexedNames();
         names[0] = "Zara";
         names[1] = "Riz";
         names[2] = "Nuha";
         names[3] = "Asif";
         names[4] = "Davinder";
         names[5] = "Sunil";
         names[6] = "Rubic";
         
         //using the first indexer with int parameter
         for (int i = 0; i < IndexedNames.size; i++) {
            Console.WriteLine(names[i]);
         }
         
         //using the second indexer with the string parameter
         Console.WriteLine(names["Nuha"]);
         Console.ReadKey();
      }
   }
}

When the above code is compiled and executed, it produces the following result −

Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.
2
Advertisements