Author : Rahul
Last Modified : 15-Jul-2021
Complexity : Intermediate

Indexers, Overload Indexers, Generic Indexer in C#


Definition:
An indexer allows an instance of a class can be used as an array. You can then use the instance of the class using [ ].

Syntax:

  [access_specifier]
  [return_type] this[parameter_list]
  {
    get
    {
      // get code here
    }
    set
    {
      // set code here
    }
  }

Syntex Explanation:

access_specifier: It can be public, private, protected or internal. 
return_type: It can be any valid C# data type. 
this: It specify the object of the current class. 
parameter_list: It specifies the parameter list. 
get: It is used to get values. 
set: It is used to set values.

Example:

// C# program to define Indexer
  using System; 
  public class IndexerTest
  {

    private int[] marks = new int[5];

    // Indexer declaration
    // public - access specifier of the Indexer
    // int - the return type of the Indexer
    // this - instance of current class
    // index - parameter list of the Indexer
    public int this[int index]
    {
      // Used to get value
      get
      {
        return marks[index];
      }

      // Used to set values
      set
      {
        marks[index] = value;
      }
    }
  }

  class IndexerMain
  {
    public static void Main()
    {

      IndexerTest iTest = new IndexerTest();
      iTest[0] = 10;
      iTest[1] = 20;

      Console.Write("Indexer Values:\n");
      Console.WriteLine("First value = {0}", iTest[0]);
      Console.WriteLine("Second value = {0}", iTest[1]);

    }
  }

Output:

Indexer Values: 
First value = 10 
Second value = 20

Another Example:

// C# program for Indexer
using System;
 
  public class IndexerTest
  {

    private string[] studentName = new string[10];
    private static int size = 10;

    public IndexerTest()
    {
      for (int i = 0; i < size; i++)
        studentName[i] = "N. A.";
    }

    // Indexer declaration
    public string this[int index]
    {
      // Used to get value
      get
      {
        if (index >= 0 && index < size)
        {
          return studentName[index];
        }
        else
        {
          return "";
        }
      }

      // Used to set values
      set
      {
        if (index >= 0 && index < size)
        {
          studentName[index] = value;
        }
      }
    }
  }

  class IndexerMain
  {
    public static void Main()
    {

      IndexerTest iTest = new IndexerTest();
      iTest[1] = "Rahul";
      iTest[2] = "Om";

      Console.Write("Student Name:\n");
      Console.WriteLine("First Name = {0}", iTest[0]);
      Console.WriteLine("Second Name = {0}", iTest[1]);
      Console.WriteLine("Third Name = {0}", iTest[2]);
    }
  }

Output:

Student Name: 
First Name = "N. A." 
Second Name = "Rahul" 
Third Name = "Om"

 

Overloaded Indexers

Indexers can be overloaded. Below code is used to understand Overloaded Indexers:

// C# program for Indexer
using System;

  public class IndexerTest
  {
    private string[] studentName = new string[10];
    private static int size = 10;

    public IndexerTest()
    {
      for (int i = 0; i < size; i++)
        studentName[i] = "N. A.";
    }

    // int type indexer
    public string this[int index]
    {
      // Used to get value
      get
      {
        if (index >= 0 && index < size)
        {
          return studentName[index];
        }
        else
        {
          return "";
        }
      }

      // Used to set values
      set
      {
        if (index >= 0 && index < size)
        {
          studentName[index] = value;
        }
      }
    }

    // string type indexer
    public string this[string name]
    {
      get
      {
        foreach (string str in studentName)
        {
          if (str.ToLower() == name.ToLower())
            return str;
        }

        return null;
      }
    }
  }

  class IndexerMain
  {
    static void Main(string[] args)
    {
      IndexerTest iTest = new IndexerTest();

      iTest[0] = "Rahul";
      iTest[1] = "Amit";
      iTest[2] = "Om";

      Console.Write("Student Name(With int indexer):\n");
      Console.WriteLine("First Name = {0}", iTest[0]);
      Console.WriteLine("Second Name = {0}", iTest[1]);
      Console.WriteLine("Third Name = {0}", iTest[2]);

      Console.Write("Student Name(With string indexer):\n");
      Console.WriteLine("First Name = {0}", iTest["Rahul"]);
      Console.WriteLine("Second Name = {0}", iTest["Amit"]);
      Console.WriteLine("Third Name = {0}", iTest["Om"]);
    }
  }

Output:

Student Name(With int indexer): 
First Name = "Rahul" 
Second Name = "Amit" 
Third Name = "Om" 

Student Name(With string indexer): 
First Name = "Rahul" 
Second Name = "Amit" 
Third Name = "Om"

 

Generic Indexers

Indexer can be generic. Below code is used to understand Generic Indexers:

// C# program for Indexer
using System;

  public class GenericData<T>
  {
    private T[] data;

    public GenericData()
    {
      data = new T[10];
    }

    public GenericData(int len)
    {
      data = new T[len];
    }

    public T this[int index]
    {
      get
      {
        return data[index];
      }

      set
      {
        data[index] = value;
      }
    }
  }

  class IndexerMain
  {
    public static void Main()
    {

      GenericData<int> idata = new GenericData<int>();
      idata[0] = 10;
      idata[1] = 20;

      Console.Write("Indexers with int data:\n");
      Console.WriteLine("First Value = {0}", idata[0]);
      Console.WriteLine("Second Value = {0}", idata[1]);

      GenericData<string> sdata = new GenericData<string>();
      sdata[0] = "Rahul";
      sdata[1] = "Om";

      Console.Write("Indexers with string data:\n");
      Console.WriteLine("First Value = {0}", sdata[0]);
      Console.WriteLine("Second Value = {0}", sdata[1]);

    }
  }

Output:

Indexers with int data: 
First Value = 10 
Second Value = 20 

Indexers with string data: 
First Value = "Rahul" 
Second Value = "Om"

 

Indexers in Interface

Indexers can also be declared in Interfaces. Below code is used to understand Indexers in Interfaces:

// C# program for Indexer
using System;

  interface IIndexer
  {
    string this[int index] { get; set; }
  }

  public class IndexerTest : IIndexer
  {

    private string[] studentName = new string[10];
    private static int size = 10;

    public IndexerTest()
    {
      for (int i = 0; i < size; i++)
        studentName[i] = "N. A.";
    }

    // Indexer declaration
    public string this[int index]
    {
      // Used to get value
      get
      {
        if (index >= 0 && index < size)
        {
          return studentName[index];
        }
        else
        {
          return "";
        }
      }

      // Used to set values
      set
      {
        if (index >= 0 && index < size)
        {
          studentName[index] = value;
        }
      }
    }
  }

  class IndexerMain
  {
    public static void Main()
    {

      IndexerTest iTest = new IndexerTest();
      iTest[1] = "Rahul";
      iTest[2] = "Om";

      Console.Write("Student Name:\n");
      Console.WriteLine("First Name = {0}", iTest[0]);
      Console.WriteLine("Second Name = {0}", iTest[1]);
      Console.WriteLine("Third Name = {0}", iTest[2]);
    }
  }

Output:

Student Name: 
First Name = "N. A." 
Second Name = "Rahul" 
Third Name = "Om"

 

Indexers in Abstract Class

Indexers can also be declared in Abstract Classes. Below code is used to understand Indexers in Abstract Classes:

// C# program for Indexer
using System;
  public abstract class AbstractIndexer
  {
    public abstract string this[int index] { get; set; }
  }

  public class IndexerTest : AbstractIndexer
  {

    private string[] studentName = new string[10];
    private static int size = 10;

    public IndexerTest()
    {
      for (int i = 0; i < size; i++)
        studentName[i] = "N. A.";
    }

    // Indexer declaration
    public override string this[int index]
    {
      // Used to get value
      get
      {
        if (index >= 0 && index < size)
        {
          return studentName[index];
        }
        else
        {
          return "";
        }
      }

      // Used to set values
      set
      {
        if (index >= 0 && index < size)
        {
          studentName[index] = value;
        }
      }
    }
  }

  class IndexerMain
  {
    public static void Main()
    {

      IndexerTest iTest = new IndexerTest();
      iTest[1] = "Rahul";
      iTest[2] = "Om";

      Console.Write("Student Name:\n");
      Console.WriteLine("First Name = {0}", iTest[0]);
      Console.WriteLine("Second Name = {0}", iTest[1]);
      Console.WriteLine("Third Name = {0}", iTest[2]);
    }
  }

Output:

Student Name: 
First Name = "N. A." 
Second Name = "Rahul" 
Third Name = "Om"

 

Inheritance in Indexers

Inheritance is also supported by Indexers. Below code is used to understand Indexers in Interfaces:

// C# program for Indexer
using System;
  public class IndexerBase
  {
    public string this[int index]
    {
      get
      {
        return "Base";
      }
      set
      {
      }
    }
  }

  public class IndexerDerived : IndexerBase
  {

    private string[] studentName = new string[10];
    private static int size = 10;

    public IndexerDerived()
    {
      for (int i = 0; i < size; i++)
        studentName[i] = "N. A.";
    }

    // Indexer declaration
    public string this[int index]
    {
      // Used to get value
      get
      {
        if (index >= 0 && index < size)
        {
          return studentName[index];
        }
        else
        {
          return "";
        }
      }

      // Used to set values
      set
      {
        if (index >= 0 && index < size)
        {
          studentName[index] = value;
        }
      }
    }
  }

  class IndexerMain
  {
    public static void Main()
    {

      IndexerBase iBase = new IndexerDerived();
      iBase[1] = "Rahul";
      iBase[2] = "Om";

      Console.Write("Student Name:\n");
      Console.WriteLine("First Name = {0}", iBase[0]);
      Console.WriteLine("Second Name = {0}", iBase[1]);
      Console.WriteLine("Third Name = {0}", iBase[2]);
    }
  }

Output:  

Student Name: 
First Name = "N. A." 
Second Name = "Rahul" 
Third Name = "Om"

 

Polymorphism in Indexers

Run time polymorphism are also supported by Indexers. Below code is used to understand Indexers in Interfaces:

// C# program for Indexer
using System;
  public class IndexerBase
  {
    public virtual string this[int index]
    {
      get
      {
        return "Base";
      }
      set
      {
      }
    }
  }

  public class IndexerDerived : IndexerBase
  {

    private string[] studentName = new string[10];
    private static int size = 10;

    public IndexerDerived()
    {
      for (int i = 0; i < size; i++)
        studentName[i] = "N. A.";
    }

    // Indexer declaration
    public override string this[int index]
    {
      // Used to get value
      get
      {
        if (index >= 0 && index < size)
        {
          return studentName[index];
        }
        else
        {
          return "";
        }
      }

      // Used to set values
      set
      {
        if (index >= 0 && index < size)
        {
          studentName[index] = value;
        }
      }
    }
  }

  class IndexerMain
  {
    public static void Main()
    {

      IndexerBase iBase = new IndexerDerived();
      iBase[1] = "Rahul";
      iBase[2] = "Om";

      Console.Write("Student Name:\n");
      Console.WriteLine("First Name = {0}", iBase[0]);
      Console.WriteLine("Second Name = {0}", iBase[1]);
      Console.WriteLine("Third Name = {0}", iBase[2]);
    }
  }

Output:

Student Name: 
First Name = "N. A." 
Second Name = "Rahul" 
Third Name = "Om"

Points to Remember

  1. Indexers require this keyword to create.
  2. If a property contains a parameter, it is called an indexer.
  3. Indexers are implemented using [] inside get and set.
  4. Indexers have not contained ref and out parameter.
  5. Indexers are identified by their parameter list.
  6. Indexers can be overloaded.
  7. Indexers are class instance, so can't be static.

Difference between Indexers and Properties

IndexersProperties
Indexers require this keyword to create.Properties don't require this keyword.
Indexers are identified by their parameter list.Properties are identified by their name.
Indexers can be overloaded.Properties can't be overloaded.
Indexers are accessed using array indexes.Properties are accessed using their name.
Indexers are class instance, so can't be static.Properties can be static.
Parameter can be passed in Indexers.Parameter can't be passed in Properties.