Take advantage of indexers in C# to access an instance of a class or a struct by using indexes The C# programming language includes support for indexers — a feature that enables you to use an object just as an array. Indexers are also known as smart arrays and can be defined similar to how a property is defined. The MSDN states: “Indexers allow instances of a class or struct to be indexed just like arrays. Indexers resemble properties except that their accessors take parameters.” Although indexers and properties have similarities in more ways than one, there are subtle differences between them. Unlike properties, you can access an indexer using indexes. Remember that you need to access a property by using its name. Also, indexers are instance members of a class and hence they cannot be static. You can have both static and non-static properties. The following code snippet illustrates how an indexer is declared: <Modifier> <Return type> this [argument list] { get { } Set { } } Note that the modifier as shown in the syntax declaration of an indexer can be private, public, protected or internal. Consider the following class: public class Contact { private string[] address = new string[3]; public string this[int index] { get { return address[index]; } set { address[index] = value; } } } The Contact class contains a private member named address and defines an indexer. The address member is an array of type string. Here’s how you can create an instance of the Contact class and use the indexer. Contact contact = new Contact(); contact[0] = "Begumpet"; contact[1] = "Hyderabad"; contact[2] = "Telengana"; for (int i = 0; i < 3; i++) Console.WriteLine (contact[i]); It should be noted that you need to use the “this” keyword to define indexers. Note that you are not constrained to using only integers as indexes to access indexers — you can even use other lookup mechanisms as well. An indexer is typically used when your class represents a collection or objects. You can then use indexer to access a specific element using index. Let’s try an example. Consider the following class named Customer. public class Customer { public List<Order> Orders { get; set; } public Order this[int orderID] { get { return (from o in Orders where o.OrderID == orderID select o).First(); } } } The Customer class defines an indexer of type Order. It also contains a public property that is a list of type Order. Here’s the Order class for your reference. public class Order { public int OrderID { get; set; } } The following code snippet illustrates how you can access the indexer of the Customer class to retrieve a particular order. List<Order> lstOrder = new List<Order>(); Order o1 = new Order(); o1.OrderID = 1; Order o2 = new Order(); o2.OrderID = 2; lstOrder.Add(o1); lstOrder.Add(o2); Customer customer = new Customer(); customer.Orders = lstOrder; Order o = customer[1]; Refer to the code snippet above. Note how a generic list of type Order has been created and assigned to the Orders property of an instance of the Customer class. Next, you just pass the OrderId as a parameter to retrieve the particular order instance. Indexers support inheritance, can be polymorphic and can also be abstract. Consider the following class that defines an indexer that is virtual. The ContactBase class is modified version of the Contact class we discussed earlier in this article. public class ContactBase { protected string[] address = new string[3]; public virtual string this[int index] { get { return address[index]; } set { address[index] = value; } } } You can now derive a class from the ContactBase class and override the indexer as shown below. public class ConcreteContact: ContactBase { public override string this[int index] { get { return address[index]; } set { address[index] = value; } } } So, in the code example above, we explored how indexers can be used while inheriting types and how they can show polymorphic behavior. You can just as well define an indexer as abstract. To do this, you need to create an abstract class and then define an indexer as abstract inside it. Let’s modify the ContactBase class and define the indexer as abstract. Here’s how the modified version of the ContactBase class would now look: public abstract class ContactBase { protected string[] address = new string[3]; public abstract string this[int index] { get; set; } } You don’t need to change the ConcreteContact class anyway. You can now leverage the indexer to assign string values to an instance of the ConcreteContact class as shown below. ConcreteContact contact = new ConcreteContact(); contact[0] = "Begumpet"; contact[1] = "Hyderabad"; contact[2] = "Telengana"; Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos