Introduction
The first impression of most developers I’ve encountered when they experienced indexers is, they felt like it was an array. It is because instances of a class or struct which uses indexers are behaving like an array. However; don’t be confused -- indexers aren’t arrays, but they appear to be. Let us try to answer, what is an indexer? In the next section.
What is an Indexer?
Indexers are like properties which accept arguments and indexer object can be indexed in the same way an array does. In addition, because it is like properties it can have access modifiers such as public, private, protected or internal. Then last but not least, we can’t ignore the getters and setters of course. The purpose of the indexer is basically to simply the syntax (syntactic sugar).
The difference between Properties and Indexers
| Properties | Indexers |
| An instance or static member | Instance member only |
| Accessed via a name | Accessed via an index |
| Getters has no parameters | Getters has the same formal parameter list as the indexer |
| Setters uses implicit value parameter. | Setters of an index have the same formal parameter list of the indexer and to the value parameter. |
| Supports auto-implemented properties | Doesn’t support auto implemented properties. |
When to use Indexer?
- If you need a collection of its instances.
- If you need a collection of values directly related to your instance.
Examples
- If you need a collection of its instances.
Now let us try to make a unit-test so could see how indexers work.
- using System;
- using System.Linq;
- namespace CSharpIndexFeatureExplore {
- public enum Title {
- MR = 0,
- MS = 1
- }
- public class Customer {
- public Customer () : this (5) { }
- public Customer (int lengthOfCustomers) {
- this._customers = new Customer[lengthOfCustomers];
- }
- public Title Title { get; set; }
- public string TitleInString {
- get {
- string title = Title.ToString ();
- return new string (title.Select ((ch, index) => (index == 0) ? ch : Char.ToLower (ch)).ToArray ());
- }
- }
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public int CustomersLength { get { return this._customers.Length; } }
- private readonly Customer[] _customers;
- public Customer this [int index] {
- get { return this._customers[index]; }
- set { this._customers[index] = value; }
- }
- public override string ToString () => $"{this.TitleInString}. {this.LastName}, {this.FirstName}";
- }
- }
- using System;
- using CSharpIndexFeatureExplore;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
- namespace UnitTestProject1 {
- [TestClass]
- public class IndexFeatureInstanceList {
- private Customer _customer;
- [TestInitialize ()]
- public void TestInit () {
- this._customer = new Customer (5) { };
- this.Initialize_Customer_Collection ();
- }
- private void Initialize_Customer_Collection () {
- this._customer[0] = new Customer { Title = Title.MR, FirstName = "Red", LastName = "Ford" };
- this._customer[1] = new Customer { Title = Title.MS, FirstName = "Anne", LastName = "Green" };
- this._customer[2] = new Customer { Title = Title.MR, FirstName = "Jack", LastName = "Robinsons" };
- this._customer[3] = new Customer { Title = Title.MS, FirstName = "Michelle", LastName = "Miguelito" };
- this._customer[4] = new Customer { Title = Title.MS, FirstName = "Trix", LastName = "Delacruz" };
- }
- [TestMethod]
- [Priority (1)]
- public void Test_Create_Instances_Of_Customer_Class () {
- Assert.IsNotNull (_customer);
- Assert.IsTrue (_customer.CustomersLength > 0);
- }
- [TestMethod]
- [Priority (2)]
- public void Test_Loop_Throught_Customer_Instances () {
- int length = this._customer.CustomersLength;
- for (int i = 0; i < length; i++) {
- Console.WriteLine (this._customer[i].ToString ());
- }
- }
- }
- }
- If you need a collection of values directly related to your instance.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Runtime.CompilerServices;
- namespace CSharpIndexFeatureExplore {
- public enum FoodType {
- JUNK = 0,
- GO = 1,
- GROW = 2
- }
- public class Food {
- private Dictionary<FoodType, string[]> foodCollection;
- public Food () {
- foodCollection = new Dictionary<FoodType, string[]> { { FoodType.JUNK, new string[] { "Potato Chips", "Sweet Potato Chips" } },
- { FoodType.GO, new string[] { "Sweet Potatoes", "Rice", "Pasta", "Bread" } },
- { FoodType.GROW, new string[] { "Chicken", "Eggs", "Fish", "Meat" } }
- };
- }
- public int FruitsLength { get; set; }
- [IndexerName ("FoodPyramid")]
- public string[] this [FoodType index, string foodType = ""] {
- get {
- return foodCollection[index];
- }
- set {
- if (!Enum.GetNames (typeof (FoodType)).Any (f => f == foodType)) {
- throw new ApplicationException ("Food type not available");
- }
- foodCollection[index] = value;
- }
- }
- }
- }
- Imports CSharpIndexFeatureExplore
- Module Module1
- Sub Main()
- Dim fruits As New Food()
- Dim myCollectionOfFruits = fruits.FoodPyramid(1)
- For Each item As String In myCollectionOfFruits
- Console.WriteLine(item)
- Next
- End Sub
- End Module
- using System;
- using System.Collections.Generic;
- using CSharpIndexFeatureExplore;
- using Microsoft.VisualStudio.TestTools.UnitTesting;
- namespace UnitTestProject1 {
- [TestClass]
- public class IndexFeaturesRepresentsList {
- private Food _food;
- [TestInitialize ()]
- public void Init () {
- this._food = new Food ();
- }
- [TestMethod]
- public void Test_Get_FoodPyramid () {
- var foodTypes = (FoodType[]) Enum.GetValues (typeof (FoodType));
- foreach (var foodType in foodTypes) {
- var results = this._food[foodType, foodType.ToString ()];
- Assert.IsNotNull (results);
- Assert.IsTrue (results.Length > 0);
- foreach (var food in results) {
- Console.WriteLine ($"{foodType.ToString()} => {food} ");
- }
- }
- }
- [TestMethod]
- [ExpectedException (typeof (KeyNotFoundException))]
- public void Test_Get_FoodPyramid_Not_Exists () {
- var food = this._food[(FoodType) 3];
- }
- [TestMethod]
- public void Test_Get_FoodPyramid_Not_Exists_Handle () {
- Exception expectedException = null;
- try {
- var food = this._food[(FoodType) 4];
- } catch (Exception ex) {
- expectedException = ex;
- }
- Assert.IsNotNull (expectedException);
- }
- }
- }
Before we go to the unit-test. Let us try to see if the "IndexerName" attribute would work with other programming language. In this scenario, we have used the VB programming language.
Again, let us try to make a unit-test so could see how indexers work in this scenario.

Sourav Kumar DasPosted Nov 5, 2019, 12:25 AM
Nice Article.