Title Image

An indexer in C# is a special type of class or struct member that allows its instances to be accessed like arrays using square brackets ( [ ] ). It acts as a shortcut to expose internal data, such as arrays, lists, or dictionaries, in a clean and intuitive way, making the object behave like a virtual array or key-value store.

Indexers are declared using the this keyword along with at least one parameter and get/set accessors. Unlike properties, which do not take parameters, indexers must take one or more parameters to determine which data element to access or modify.

🧪 Syntax

[access_modifier] [return_type] this [parameter_list]
{
    get { // return value }
    set { // assign value }
}

🎯 Why Use Indexers?

👨‍💻 Example: Student Grades (Simple Indexer)

public class StudentGrades
{
    private int[] grades = new int[5];

    public int this[int index]
    {
        get { return grades[index]; }
        set { grades[index] = value; }
    }
}

Usage:

StudentGrades student = new StudentGrades();
student[0] = 85;
Console.WriteLine(student[0]);  // Output: 85

📒 String-Based Indexer (Like Dictionary)

public class PhoneBook
{
    private Dictionary<string, string> contacts = new();

    public string this[string name]
    {
        get => contacts.ContainsKey(name) ? contacts[name] : "Not Found";
        set => contacts[name] = value;
    }
}

Usage:

PhoneBook pb = new PhoneBook();
pb["Alice"] = "123-4567";
Console.WriteLine(pb["Alice"]); // Output: 123-4567

🔁 Advanced: Multiple & Overloaded Indexers

public class Indexer
{
    private int[] data = new int[10];

    // Multi-parameter indexer
    public int this[int index, bool square]
    {
        get => square ? data[index] * data[index] : data[index];
        set => data[index] = square ? (int)Math.Sqrt(value) : value;
    }

    // Overloaded indexer with string
    public int this[string key]
    {
        get
        {
            switch (key.ToLower())
            {
                case "first": return data[0];
                case "last": return data[data.Length - 1];
                default: throw new ArgumentException("Invalid key.");
            }
        }
    }

    // Read-only indexer
    public int this[int index]
    {
        get { return data[index]; }
    }
}

Usage:

Indexer i = new Indexer();
i[0, false] = 5;
Console.WriteLine(i[0, false]);  // 5
Console.WriteLine(i[1, true]);   // 0 (0 squared)
Console.WriteLine(i["first"]);   // 5
Console.WriteLine(i[2]);         // 0 (read-only)

🧾 Key Points to Remember

🔹 Feature 🔍 Description
this keyword Used to define an indexer in a class
get accessor Retrieves the value at the specified index
set accessor Assigns a value at the specified index using the value keyword
Parameters Must take at least one parameter (unlike properties)
Return type Can be any type, like int, string, object, etc.
Index types Can be int, string, or any type you define
Overloading Multiple indexers with different parameter types are allowed
Multi-dimensional You can define indexers with multiple parameters
Read-only indexer Leave out set to make an indexer read-only
Not static Indexers are always instance members (cannot be static)
Smart arrays Indexers are also called "smart arrays" or "parameterized properties"

🧰 Real-World Use Cases

📝 Conclusion

Indexers in C# offer a clean and intuitive way to interact with objects just like arrays or dictionaries. Whether you’re wrapping a collection or building a custom data structure, indexers allow you to expose data safely while improving code readability. With support for multiple parameters, string keys, and overloading, indexers make your C# code more expressive and powerful. If your class needs indexed access, like a collection or mapping, indexers are your go-to feature.