Indexer In C#

Introduction 

Indexer allows accessing the members of a class as an array. In c# indexer is also known as smart array or virtual array. We can define an indexer using "this" keyword which indicates that we are creating the indexer for the current class. Once we have defined the indexer for a class, we can access the member of that class with the help of array access operator [ ]. So, we can say that indexer is similar to property but it allows us to access a member of the class using [ ] operator.

Why do we need to use indexer?

Let's consider a simple example.

Program 1

  1. namespace StudentClass
  2. {  
  3.     public class student 
  4.     {  
  5.         Int StudId;  
  6.         string StudName;  

  7.         public student(int StudId, string StudName) 
  8.         {  
  9.             this.StudId = StudId;  
  10.             this.StudName = StudName;  
  11.         }  
  12.     }  
  13. }  

In this example, we have created a simple student class with two members and a parametrized constructor. Once we have created a class and if it is public, then we can consume that class from any other class or project.

Program 2

  1. namespace consumestudent 
  2. {  
  3.     public static void Main() 
  4.     {  
  5.         student stu = new student(1, ”Hitanshi”);  

  6.         stu[0]; //it is not accessible  
  7.     }  
  8. }  

In our second example, we have created a consumestudent class and we are creating one object of student class. By default, the scope for all members of the class is private, so we cannot access StudId and StudName outside the class. Now, if we want to access member outside a class, then there are three different mechanisms available.

  1. Declare member of a class as public
    If we declare a member of class as public then anyone outside class can get or set the value of member. As a developer, we lose control over members.

    Therefore, we should never declare a member as public. For example, if you declare a prize member as public, then anyone outside the class can set prize.

  2. Use properties
    Property allows restricted access. It allows readonly, writeonly, or read/write access. Property also allows us to set validation on the member. For example, we want to store the age only if it is greater than 18, then we can set a validation on properties before storing them into the database.

  3. Use Indexer
    Indexer is like property but it provides access to the members of class using an index value.

Syntax of Indexer

[<Modifiers>] <Type> this [<parameter list>]

Here, we use modifier as public, type as an object because it may return an integer, a string, or any other valid data type. We use "this" keyword to specify that we are declaring an indexer on the current class and the instance of the current class can have access on the members of a class. Parameter list can be any valid data type. Mostly, we use int and string as a parameter list. It means we can access the member of the class using int and string.

Where indexers are used?

We can use indexer in many ways,

Indexers are used in class.
 
Example

Inside the class, we can declare an indexer as below.

Program 1

  1. namespace StudentClass 
  2. {  
  3.     public class student 
  4.     {  
  5.         Int StudId;  
  6.         string StudName; 
  7.  
  8.         public student(int StudId, string StudName) 
  9.         {  
  10.             this.StudId = StudId;  
  11.             this.StudName = StudName;  
  12.         }  
  13.     }  
  14.     public object this[int index] 
  15.    {  
  16.         get 
  17.         {  
  18.             If(index == 0)  
  19.             return StudId;  
  20.             elseif(index == 1)  
  21.             return StudName;  
  22.         }  
  23.         set 
  24.         {  
  25.             If(index == 0)  
  26.             StudId = (int) value;  
  27.             elseif(index == 1)  
  28.             StudName = (string) value;  
  29.         }  
  30.         public object this[string name] 
  31.         {  
  32.             get 
  33.             {  
  34.                 If(name.ToUpper() == ”STUDID”)  
  35.                 return StudId;  
  36.                 elseif(name.ToUpper() = ”STUDNAME”)  
  37.                 return StudName;  
  38.             }  
  39.             set 
  40.             {  
  41.                 If(name.ToUpper() == ”STUDID”)  
  42.                 StudId = (int) value;  
  43.                 elseif(name.ToUpper() == ”STUDNAME”)  
  44.                 StudName = (string) value;  
  45.             }  
  46.         }  
  47.     }  

Here, the 'value' is an implicit variable that provide access to the value assigned by the user. The data type of the value will be the same as indexer so in our case, the value will be of object type. As value is object type, we need to perform the unboxing by converting the object into int or string.

Integral indexer
 
In integral indexer, it is not compulsory to start an index with 0. We can start index with 1 but as indexer is behaving like a virtual array, we are starting our first index with 0 which will point to StudId. In this example, we have overloaded the indexer using int and string.
 
String indexer 
 
One of the biggest problems with string indexer is that C# is case sensitive. To solve this problem, we have used ToUpper(). This code will work even if the user enters the StudId in lower case because we are converting the name indexer to uppercase and checking it with uppercase.

  1. namespace consumestudent 
  2. {  
  3.     public static void Main() 
  4.    {  
  5.         student stu = new student(11, ”Hitanshi”);  
  6.         stu[1] = ”HITANSHI”; 
  7.  
  8.         Console.WriteLine(“Student Id” + stu[“Studid”]);  
  9.         Console.WriteLine(“Student name” + stu[“Studname”]);  
  10.     }  
  11. }  
Output

11 HITANSHI

To store or retrieve the data from session state or application state, we use an indexer.
  1. namespace program {  
  2.     protected void page_Load(object sender, EventArgs a) 
  3.     {  
  4.         session[“data1”] = ”Show data1”;  
  5.         session[“data2”] = ”Show data2”; 
  6.  
  7.         Response.WritLine(“Session1 stores” + session[0].ToString());  
  8.         Responser.WritLine(“Session2 stores” + session[“data2”].ToString());  
  9.     }  
  10. }  
So here, we have created the first session using “data1” string indexer but when we are printing the data, we are using integral indexer. We have used 0 as index so it will pull the data that is present in the first session key. Here, we have used ToString() because Session actually returns an object data type but we know that it is string, so we are going to convert it into string.
 
To retrieve the data from the specific column when we are looping through “SqlDataReader” object, we can use either the integral indexer or string indexer.
  1. using(SqlConnection con = new SqlConnection(cs)) 
  2.     {  
  3.     SqlCommand cmd = new SqlCommand(“select * from employee”, con);  
  4.     con.open();  
  5.     SqlDataReader rd = cmd.ExecuteReader(); 
  6.  
  7.     while (rd.Read()) 
  8.     {  
  9.         Response.WritLine(“Id = ”+rd[0].ToString());  
  10.         Response.WritLine(“Name = ”+rd[“name”].ToString());  
  11.     }  
  12. }  

As illustrated in the example, we can get data from database with the help of string or integer indexer.

Therefore, in .NET Framework many classes are already using indexer.