Indexers Usage in C#


Indexers nothing but custom types in Class which provides the access to internal sub types using array like syntax. That means in C# indexers acts like virtual arrays for a class. If we have an indexer in a class, then you can index that class instances. You can create the indexers for structures also in C#. Indexer must contains get method and it can contains set method. Indexer much like a mangled property in C# and created by using this[] syntax. In this article we will discuss about how to create indexer and how to access properties of a class by using indexer in C# with example.

Open Microsoft Visual Studio 2015 => Create New Project and select Windows Application from available templates => name it as CSharpIndexer.

Add some XML file to the project as data source as shown below.

Employee.xml

<?xml version="1.0" standalone="yes"?>

<Employees>

  <Employee>

    <Id>100</Id>

    <Name>John</Name>

    <Location>Houston</Location>

    <Salary>30000</Salary>

  </Employee>

  <Employee>

    <Id>101</Id>

    <Name>Dany</Name>

    <Location>Houston</Location>

    <Salary>30000</Salary>

  </Employee>

  <Employee>

    <Id>102</Id>

    <Name>Smitha</Name>

    <Location>Newyork</Location>

    <Salary>5000</Salary>

  </Employee>

  <Employee>

    <Id>103</Id>

    <Name>Mark</Name>

    <Location>New Jersey</Location>

    <Salary>66000</Salary>

  </Employee>

</Employees>

Let’s add C# class to the project and add indexer to that class shown below.

Employee.cs

using System;

using System.Data;

 

namespace CSharpIndexer

{

    public class Employee

    {

        public int Id { get; set; }

        public string Name { get; set; }

        public string Location { get; set; }

        public double Salary { get; set; }

 

        public Employee this[int iId]

        {

            get { return GetEmployeeDetails(iId); }

            set { SaveEmployeeDetails(iId, value); }

        }

 

        private Employee GetEmployeeDetails(int iId)

        {

            DataSet ds = new DataSet();

            ds.ReadXml("../../Employees.xml");

 

            Employee objEmp = new Employee();

 

            foreach (DataRow dr in ds.Tables[0].Rows)

            {

                if (Convert.ToInt32(dr["Id"]) == iId)

                {

                    objEmp.Id = Convert.ToInt32(dr["Id"]);

                    objEmp.Name = Convert.ToString(dr["Name"]);

                    objEmp.Location = Convert.ToString(dr["Location"]);

                    objEmp.Salary = Convert.ToDouble(dr["Salary"]);

 

                    break;

                }

            }

 

            return objEmp;

        }

 

        private void SaveEmployeeDetails(int iId, Employee obj)

        {

            DataSet ds = new DataSet();

            ds.ReadXml("../../Employees.xml");

 

            Employee objEmp = new Employee();

 

            foreach (DataRow dr in ds.Tables[0].Rows)

            {

                if (Convert.ToInt32(dr["Id"]) == iId)

                {

                    dr["Name"] = obj.Name;

                    dr["Location"] = obj.Location;

                    dr["Salary"] = obj.Salary;

 

                    break;

                }

            }

 

            ds.Tables[0].WriteXml("../../Employees.xml");

        }

    }

}

 

As shown above we have indexer method with Get and Set methods. Get method returns the values and Set method takes the values. Let’s call the Employee.cs class by using indexer as shown below.

using System;

using System.Windows.Forms;

 

namespace CSharpIndexer

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void Form1_Load(object sender, EventArgs e)

        {          

        }

 

        private void btnGet_Click(object sender, EventArgs e)

        {

            int iId = 0;

            Int32.TryParse(txtId.Text, out iId);

 

            if (iId <= 0)

            {

                MessageBox.Show("Please enter valid Employee Id");

                return;

            }

            else

            {

                Employee obj = new Employee();

 

                txtName.Text = obj[iId].Name;

                txtLocation.Text = obj[iId].Location;

                txtSalary.Text = obj[iId].Salary.ToString();

            }

        }

 

        private void btnSave_Click(object sender, EventArgs e)

        {

            int iId = 0;

            Int32.TryParse(txtId.Text, out iId);

 

            double dSal = 0;

            Double.TryParse(txtSalary.Text, out dSal);

 

            if (iId <= 0 || dSal <= 0 || txtName.Text.Trim().Length == 0 || txtLocation.Text.Trim().Length == 0)

            {

                MessageBox.Show("Please enter valid Employee details");

                return;

            }

            else

            {

                Employee obj = new Employee();

 

                obj[Convert.ToInt32(txtId.Text)] = new Employee { Name = txtName.Text, Location = txtLocation.Text, Salary = Convert.ToDouble(txtSalary.Text) };

 

                MessageBox.Show("Employee details saved successfully");

            }

        }

    }

}

 

 

As shown above we have two buttons, one button displays the employee details by providing the employee id to the Employee class indexer method and another button saves the input employee details by providing employee object as input to the Employee class indexer method.

Indexers can be overloaded like methods. That means we can have more than one indexer in a class but with difference in signature as shown below.

using System;

using System.Data;

 

namespace CSharpIndexer

{

    public class Employee

    {

        public int Id { get; set; }

        public string Name { get; set; }

        public string Location { get; set; }

        public double Salary { get; set; }

 

        public Employee this[int iId]

        {

            get { return GetEmployeeDetails(iId); }

            set { SaveEmployeeDetails(iId, value); }

        }

 

        public Employee this[int iId, string Name]

        {

            get { return GetEmployeeDetails(iId); }

            set { SaveEmployeeDetails(iId, value); }

        }

 

        public Employee this[int iId, string Name, string Location]

        {

            get { return GetEmployeeDetails(iId); }

            set { SaveEmployeeDetails(iId, value); }

        }

 

        .........

        .........

        .........

        .........

        .........

        .........

    }

}

 

Below As shown above we have three indexers in Employee class but with different signature (signature means different number of parameters or(and) different data types).

Indexers can defined on interface also. Class that implementing the interface must implement the interface indexer as shown below.

public interface IEmployee

{

        string this[int iId] { get; set; }

}

 

public class Employee : IEmployee

{

        public string this[int iId]

        {

            get

            {

                return "Employee Name";          

            }

            set

            {

                //Set values               

            }

        }

}

 

Here we have an interface IEmployee with indexer. Employee class implementing the IEmployee interface, so it must implement IEmployee indexer method.


                                                                                                                          CSharpIndexer.zip (57.9KB)