Skip to footer content
.NET HELP

C# Indexers (How It Works For Developers)

An indexer in C# is a special type of property that makes instances of a class or struct to be accessed using the array access operator []. Indexers can be very useful in creating "smart arrays" or encapsulating data in a simplified syntax. They provide a way to use instances of a class just like you would use arrays, where you can access data via an index. This article will explore how to declare and use C# indexers with practical examples. And we'll also explore the IronPDF library at the end of the article.

Basic Indexer Syntax

An indexer is an instance member using the this keyword in a class or struct, followed by the indexer declaration. You also specify the parameter types and the return type. The general syntax for an indexer instance member looks like this:

public return_type this[parameter_type index]
{
    get
    {
        // Code to return data
    }
    set
    {
        // Code to set data
    }
}
public return_type this[parameter_type index]
{
    get
    {
        // Code to return data
    }
    set
    {
        // Code to set data
    }
}
$vbLabelText   $csharpLabel

Here, return_type is the value type that the indexer will return such as an integer value, and parameter_type is the type of the index, often an int. The get accessor returns the value at the specified index, and the set block code accessor assigns a value to that index.

Indexer Declaration and Use

We'll examine a basic illustration of implementing an indexer within a C# class. Consider a class Program that encapsulates an array of strings.

class Program
{
    private string[] values = new string[5]; // Array with 5 elements
    public string this[int index]
    {
        get
        {
            return values[index];
        }
        set
        {
            values[index] = value;
        }
    }
}
class Program
{
    private string[] values = new string[5]; // Array with 5 elements
    public string this[int index]
    {
        get
        {
            return values[index];
        }
        set
        {
            values[index] = value;
        }
    }
}
$vbLabelText   $csharpLabel

In the above code:

  • The Program class contains a string array named values.
  • The string this[int index] is the indexer declaration, where the int index is the index parameterized property used to access elements of the array.
  • The get accessor returns the indexed value at the specified index, and the set accessor assigns an indexed value to that index.

This means you can create an instance of the Program class and access its values array using the indexer, like this:

class Program
{
    static void Main()
    {
        Program program = new Program();
        // Set values using indexer
        program[0] = "First";
        program[1] = "Second";
        // Access values using indexer
        Console.WriteLine(program[0]); // Output: First
        Console.WriteLine(program[1]); // Output: Second
    }
}
class Program
{
    static void Main()
    {
        Program program = new Program();
        // Set values using indexer
        program[0] = "First";
        program[1] = "Second";
        // Access values using indexer
        Console.WriteLine(program[0]); // Output: First
        Console.WriteLine(program[1]); // Output: Second
    }
}
$vbLabelText   $csharpLabel

In this code, you see that the indexer provides a simple syntax for accessing the values array, similar to how you would access elements in an array.

Understanding the get and set Accessors

The get and set accessors inside the indexer are like block code that allows you to retrieve and assign data similarly to how you would with properties. The main difference is that indexers use an index parameter to work with collections of data rather than individual data members.

The get block is responsible for returning the data at the specified index, while the set block assigns data to the specified index. Here’s another example to solidify your understanding:

class StudentRecords
{
    private string[] studentNames = new string[3];
    public string this[int index]
    {
        get
        {
            if (index >= 0 && index < studentNames.Length)
            {
                return studentNames[index];
            }
            return "Invalid Index";
        }
        set
        {
            if (index >= 0 && index < studentNames.Length)
            {
                studentNames[index] = value;
            }
        }
    }
    public int Length
    {
        get { return studentNames.Length; }
    }
}
class StudentRecords
{
    private string[] studentNames = new string[3];
    public string this[int index]
    {
        get
        {
            if (index >= 0 && index < studentNames.Length)
            {
                return studentNames[index];
            }
            return "Invalid Index";
        }
        set
        {
            if (index >= 0 && index < studentNames.Length)
            {
                studentNames[index] = value;
            }
        }
    }
    public int Length
    {
        get { return studentNames.Length; }
    }
}
$vbLabelText   $csharpLabel

In this example:

  • The StudentRecords class has a private string[] studentNames array that holds the names of students.
  • The indexer checks if the index is within the bounds of the array before setting or retrieving the value.
  • An int type Length property provides access to the length of the array.

You can use this class in the Main method as follows:

class Program
{
    public static void Main()
    {
        StudentRecords records = new StudentRecords();
        // Set values using indexer
        records[0] = "John";
        records[1] = "Jane";
        records[2] = "Bob";
        // Access values using indexer
        for (int i = 0; i < records.Length; i++)
        {
            Console.WriteLine(records[i]);
        }
    }
}
class Program
{
    public static void Main()
    {
        StudentRecords records = new StudentRecords();
        // Set values using indexer
        records[0] = "John";
        records[1] = "Jane";
        records[2] = "Bob";
        // Access values using indexer
        for (int i = 0; i < records.Length; i++)
        {
            Console.WriteLine(records[i]);
        }
    }
}
$vbLabelText   $csharpLabel

Creating a Generic Indexer

You can also create generic classes with indexers, allowing your code to handle multiple data types. Here’s a simple example of a generic class with a generic indexer:

class GenericClass<T>
{
    private T[] elements = new T[5];
    public T this[int index]
    {
        get
        {
            return elements[index];
        }
        set
        {
            elements[index] = value;
        }
    }
    public int Length
    {
        get { return elements.Length; }
    }
}
class GenericClass<T>
{
    private T[] elements = new T[5];
    public T this[int index]
    {
        get
        {
            return elements[index];
        }
        set
        {
            elements[index] = value;
        }
    }
    public int Length
    {
        get { return elements.Length; }
    }
}
$vbLabelText   $csharpLabel

In this code:

  • The GenericClassclass defines an indexer that can work with any data type.
  • The this[int index] indexer allows you to access the elements in the array, regardless of the type.

You can now use the GenericClass with different data types in the Main method:

class Program
{
    public static void Main()
    {
        GenericClass<int> intArray = new GenericClass<int>();
        intArray[0] = 10;
        intArray[1] = 20;

        GenericClass<string> stringArray = new GenericClass<string>();
        stringArray[0] = "Hello";
        stringArray[1] = "World";

        // Output the integer array values
        for (int i = 0; i < intArray.Length; i++)
        {
            Console.WriteLine(intArray[i]);
        }

        // Output the string array values
        for (int i = 0; i < stringArray.Length; i++)
        {
            Console.WriteLine(stringArray[i]);
        }
    }
}
class Program
{
    public static void Main()
    {
        GenericClass<int> intArray = new GenericClass<int>();
        intArray[0] = 10;
        intArray[1] = 20;

        GenericClass<string> stringArray = new GenericClass<string>();
        stringArray[0] = "Hello";
        stringArray[1] = "World";

        // Output the integer array values
        for (int i = 0; i < intArray.Length; i++)
        {
            Console.WriteLine(intArray[i]);
        }

        // Output the string array values
        for (int i = 0; i < stringArray.Length; i++)
        {
            Console.WriteLine(stringArray[i]);
        }
    }
}
$vbLabelText   $csharpLabel

Using IronPDF with C# Indexer

C# Indexers (How It Works For Developers): Figure 1 - IronPDF

IronPDF is a C# library designed for generating, editing, and converting PDFs in .NET applications. It simplifies working with PDFs for developers to create PDFs from HTML, manipulate PDF files, and handle advanced functionalities such as merging, printing, and adding signatures programmatically.

You can leverage IronPDF within your C# programs that utilize indexers to dynamically generate and manage PDF content. For example, suppose you have a class that holds HTML strings, and you want to generate PDFs for each HTML entry using an indexer. This approach streamlines PDF generation while keeping your code organized and intuitive.

using IronPdf;
using System;

class PdfGenerator
{
    private string[] htmlTemplates = new string[3];
    public string this[int index]
    {
        get { return htmlTemplates[index]; }
        set { htmlTemplates[index] = value; }
    }

    public void GeneratePdf(int index, string outputPath)
    {
        var renderer = new ChromePdfRenderer();
        var pdfDocument = renderer.RenderHtmlAsPdf(this[index]); // Access HTML string using indexer
        pdfDocument.SaveAs(outputPath);
    }
}

class Program
{
    public static void Main()
    {
        PdfGenerator pdfGen = new PdfGenerator();
        // Populate HTML templates
        pdfGen[0] = "<h1>First Document</h1><p>This is the first PDF.</p>";
        pdfGen[1] = "<h1>Second Document</h1><p>This is the second PDF.</p>";
        pdfGen[2] = "<h1>Third Document</h1><p>This is the third PDF.</p>";

        // Generate PDFs using the indexer
        pdfGen.GeneratePdf(0, "first.pdf");
        pdfGen.GeneratePdf(1, "second.pdf");
        pdfGen.GeneratePdf(2, "third.pdf");

        Console.WriteLine("PDFs generated successfully.");
    }
}
using IronPdf;
using System;

class PdfGenerator
{
    private string[] htmlTemplates = new string[3];
    public string this[int index]
    {
        get { return htmlTemplates[index]; }
        set { htmlTemplates[index] = value; }
    }

    public void GeneratePdf(int index, string outputPath)
    {
        var renderer = new ChromePdfRenderer();
        var pdfDocument = renderer.RenderHtmlAsPdf(this[index]); // Access HTML string using indexer
        pdfDocument.SaveAs(outputPath);
    }
}

class Program
{
    public static void Main()
    {
        PdfGenerator pdfGen = new PdfGenerator();
        // Populate HTML templates
        pdfGen[0] = "<h1>First Document</h1><p>This is the first PDF.</p>";
        pdfGen[1] = "<h1>Second Document</h1><p>This is the second PDF.</p>";
        pdfGen[2] = "<h1>Third Document</h1><p>This is the third PDF.</p>";

        // Generate PDFs using the indexer
        pdfGen.GeneratePdf(0, "first.pdf");
        pdfGen.GeneratePdf(1, "second.pdf");
        pdfGen.GeneratePdf(2, "third.pdf");

        Console.WriteLine("PDFs generated successfully.");
    }
}
$vbLabelText   $csharpLabel

C# Indexers (How It Works For Developers): Figure 2 - Console Output

Conclusion

C# indexers are a useful feature that helps you to make your classes and structs behave like arrays. By providing simplified syntax and flexible data access, you can create more intuitive and readable code. Whether you’re working with strings, integers, or any other data type, indexers give you the ability to encapsulate your data structure and access it using indices cleanly and efficiently.

IronPDF makes it easy to get started with a free trial that gives you access to all the features you need to create, manipulate, and render PDFs. You can take your time exploring the software, and once you're satisfied, licenses are available starting at $799.

Frequently Asked Questions

What is an indexer in C#?

An indexer in C# is a special type of property that allows instances of a class or struct to be accessed using the array access operator []. It provides a way to use instances of a class just like arrays.

How do you declare a basic indexer in C#?

A basic indexer in C# is declared using the 'this' keyword followed by the indexer declaration. You must specify the parameter types and the return type. For example: public return_type this[parameter_type index] { get; set; }.

What is the purpose of the 'get' and 'set' accessors in an indexer?

The 'get' accessor in an indexer is used to retrieve data at a specified index, while the 'set' accessor is used to assign data to a specified index. They function similarly to property accessors but are used for collections of data.

Can you provide an example of an indexer in a C# class?

Sure. Consider a class 'Program' with a private string array. The indexer allows access to this array using an integer index. For example: public string this[int index] { get { return values[index]; } set { values[index] = value; } }.

How do you create a generic indexer in C#?

A generic indexer in C# can be created within a generic class. For example, class GenericClass includes an indexer that can handle any data type. The indexer is declared as public T this[int index] { get; set; }.

How can you use indexers in C# to streamline PDF generation?

Using a library like IronPDF, you can employ indexers to manage and access HTML templates stored within a class, which are then converted into PDF documents. This approach simplifies the process of generating dynamic PDFs from multiple HTML sources.

Can you give an example of using a PDF library with an indexer?

Certainly. You can create a class that holds HTML templates in an array and use an indexer to access these templates. Then, use a PDF library to render these HTML strings as PDF documents. For instance, a class called PdfGenerator uses an indexer to access HTML and generate PDFs.

What are the advantages of using indexers in C#?

Indexers in C# provide a simplified syntax for accessing elements in a collection, making your code more intuitive and readable. They allow classes and structs to behave like arrays, enabling efficient data encapsulation and access.

How can indexers help in creating dynamic data structures in C#?

Indexers allow developers to create dynamic data structures by enabling collections to be accessed and modified using array-like syntax. This can be particularly useful in scenarios where data needs to be managed flexibly, such as in dynamic PDF content generation.

Jacob Mellor, Chief Technology Officer @ Team Iron
Chief Technology Officer

Jacob Mellor is Chief Technology Officer at Iron Software and a visionary engineer pioneering C# PDF technology. As the original developer behind Iron Software's core codebase, he has shaped the company's product architecture since its inception, transforming it alongside CEO Cameron Rimington into a 50+ person company serving NASA, Tesla, ...

Read More