Полное руководство по языку программирования С# 14 и платформе .NET 10 / Дополнительные возможности ООП в C#

Индексаторы

Начальный ⏱ 6 мин чтения 👁 2 🕓 обновлено 11.08.2026

Индексаторы позволяют индексировать объекты и обращаться к данным по индексу. Фактически с помощью индексаторов мы можем работать с объектами как с массивами. По форме они напоминают свойства со стандартными блоками get и set, которые возвращают и присваивают значение.

Формальное определение индексатора:


возвращаемый_тип this [Тип параметр1, ...]
{
	get { ... }
	set { ... }
}

В отличие от свойств индексатор не имеет названия. Вместо него указывается ключевое слово this, после которого в квадратных скобках идут параметры. Индексатор должен иметь как минимум один параметр.

Посмотрим на примере. Допустим, у нас есть класс Person, который представляет человека, и класс Company, который представляет некоторую компанию, где работают люди. Используем индексаторы для определения класса Company:


class Person
{
    public string Name { get;}
    public Person(string name) => Name=name;
}
class Company
{
    Person[] personal;
    public Company(Person[] people) => personal = people;
    // индексатор
    public Person this[int index]
    {
        get => personal[index];
        set => personal[index] = value;
    }
}

Для хранения персонала компании в классе определен массив personal, который состоит из объектов Person. Для доступа к этим объектам определен индексатор:

public Person this[int index]

Индексатор в принципе подобен стандартному свойству. Во-первых, для индексатора определяется тип в данном случае тип Person. Тип индексатора определяет, какие объекты будет получать и возвращать индексатор.

Во-вторых, для индексатора определен параметр int index, через который обращаемся к элементам внутри объекта Company.

Для возвращения объекта в индексаторе определен блок get:


get => personal[index];

Поскольку индексатор имеет тип Person, то в блоке get нам надо возвратить объект этого типа с помощью оператора return. Здесь мы можем определить разнообразную логику. В данном случае просто возвращаем объект из массива personal.

В блоке set, как и в обычном свойстве, получаем через параметр value переданный объект Person и сохраняем его в массив по индексу.


set => personal[index] = value;

После этого мы можем работать с объектом Company как с набором объектов Person:


var microsoft = new Company(new[]
{
    new Person("Tom"), new Person("Bob"), new Person("Sam"), new Person("Alice")
});
// получаем объект из индексатора
Person firstPerson = microsoft[0];
Console.WriteLine(firstPerson.Name);  // Tom
// переустанавливаем объект
microsoft[0] = new Person("Mike");
Console.WriteLine(microsoft[0].Name);  // Mike

Стоит отметить, что если индексатору будет передан некорректный индекс, который отсутствует в массиве person, то мы получим исключение, как и в случае обращения напрямую к элементам массива. В этом случае можно предусмотреть какую-то дополнительную логику. Например, проверять переданный индекс:


class Company
{
    Person[] personal;
    public Company(Person[] people) => personal = people;
    // индексатор
    public Person this[int index]
    {
        get
        {
			// если индекс имеется в массиве
            if (index >= 0 && index < personal.Length)
                return personal[index];	// то возвращаем объект Person по индексу
            else
                throw new ArgumentOutOfRangeException(); // иначе генерируем исключение
        }
        set
        {
			// если индекс есть в массиве
            if (index >= 0 && index < personal.Length)
                personal[index] = value;	// переустанавливаем значение по индексу
        }
    }
}

Здесь в блоке get если переданный индекс имеется в массиве, то возвращаем объект по индексу. Если индекса нет в массиве, то генерируем исключение. Аналогично в блоке set устанавливаем значение по индексу, если индекс есть в массиве.

Индексы

Индексатор получает набор индексов в виде параметров. Однако индексы необязательно должны представлять тип int, устанавливаемые/возвращаемые значения необязательно хранить в массиве. Например, мы можем рассматривать объект как хранилище атрибутов/свойств и передавать имя атрибута в виде строки:


User tom = new User();
// устанавливаем значения
tom["name"] = "Tom";
tom["email"] = "tom@gmail.ru";
tom["phone"] = "+1234556767";

// получаем значение
Console.WriteLine(tom["name"]); // Tom

class User
{
    string name = "";
    string email = "";
    string phone = "";
    public string this[string propname]
    {
        get
        {
            switch (propname)
            {
                case "name": return name;
                case "email": return email;
                case "phone": return phone;
                default: throw new Exception("Unknown Property Name");
            }
        }
        set
        {
            switch (propname)
            {
                case "name":
                    name = value;
                    break;
                case "email":
                    email = value;
                    break;
                case "phone":
                    phone = value;
                    break;
            }
        }
    }
}

В данном случае индексатор в классе User в качестве индекса получает строку, которая хранит название атрибута (в данном случае название поля класса).

В блоке get в зависимости от значения строкового индекса возвращается значение того или иного поля класса. Если передано неизвестное название, то генерируется исключение. В блоке set похожая логика - по индексу узнаем, для какого поля надо установить значение.

Применение нескольких параметров

Также индексатор может принимать несколько параметров. Допустим, у нас есть класс, в котором хранилище определено в виде двухмерного массива или матрицы:


class Matrix
{
    int[,] numbers = new int[,] { { 1, 2, 4 }, { 2, 3, 6 }, { 3, 4, 8 } };
    public int this[int i, int j]
    {
        get => numbers[i, j];
        set => numbers[i, j] = value;
    }
}

Теперь для определения индексатора используются два индекса - i и j. И в программе мы уже должны обращаться к объекту, используя два индекса:


Matrix matrix = new Matrix();
Console.WriteLine(matrix[0, 0]);
matrix[0, 0] = 111;
Console.WriteLine(matrix[0, 0]);

Следует учитывать, что индексатор не может быть статическим и применяется только к экземпляру класса. Но при этом индексаторы могут быть виртуальными и абстрактными и могут переопределяться в произодных классах.

Блоки get и set

Как и в свойствах, в индексаторах можно опускать блок get или set, если в них нет необходимости. Например, удалим блок set и сделаем индексатор доступным только для чтения:


class Matrix
{
    int[,] numbers = new int[,] { { 1, 2, 4 }, { 2, 3, 6 }, { 3, 4, 8 } };
    public int this[int i, int j]
    {
        get => numbers[i, j];
    }
}

Также мы можем ограничивать доступ к блокам get и set, используя модификаторы доступа. Например, сделаем блок set приватным:


class Matrix
{
    int[,] numbers = new int[,] { { 1, 2, 4 }, { 2, 3, 6 }, { 3, 4, 8 } };
    public int this[int i, int j]
    {
        get => numbers[i, j];
        private set => numbers[i, j] = value;
    }
}

Перегрузка индексаторов

Подобно методам индексаторы можно перегружать. В этом случае также индексаторы должны отличаться по количеству, типу или порядку используемых параметров. Например:


var microsoft = new Company(new Person[] { new("Tom"), new("Bob"), new("Sam") });

Console.WriteLine(microsoft[0].Name);      // Tom
Console.WriteLine(microsoft["Bob"].Name);  // Bob
class Person
{
    public string Name { get;}
    public Person(string name) => Name=name;
}
class Company
{
    Person[] personal;
    public Company(Person[] people) => personal = people;
    // индексатор
    public Person this[int index]
    {
        get => personal[index];
        set => personal[index] = value;
    }

    public Person this[string name]
    {
        get
        {
            foreach (var person in personal)
            {
                if (person.Name == name) return person;
            }
            throw new Exception("Unknown name");
        }
    }
}

В данном случае класс Company содержит две версии индексатора. Первая версия получает и устанавливает объект Person по индексу, а вторая - только получае объект Person по его имени.

Дополнительные материалы

Проверь себя

📋 Тест по теме «Индексаторы» Тест по теме

Практические задания

Лёгкое Ручная проверка Заполните пропуск в коде (1)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

возвращаемый_тип _____ [Тип параметр1, ...]
{
	get { ... }
	set { ... }
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (2)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

class Person
{
    public string _____ { get;}
    public Person(string name) => Name=name;
}
class Company
{
    Person[] personal;
    public Company(Person[] people) => personal = people;
    // индексатор
    public Person this[int index]
    {
        get => personal[index];
        set => personal[index] = value;
    }
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (3)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

public Person this[int _____]
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (4)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

_____ => personal[index];
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (5)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

_____ => personal[index] = value;
Войдите, чтобы отправить решение
Среднее Ручная проверка Восстановите код по памяти (1)
+20 XP

В этом фрагменте кода урока пропущены два ключевых элемента. Впишите оба пропущенных значения через запятую в порядке появления (например: x, 5).

возвращаемый_тип this [Тип параметр_____, ...]
{
	_____ { ... }
	set { ... }
}
Войдите, чтобы отправить решение
Среднее Ручная проверка Восстановите код по памяти (2)
+20 XP

В этом фрагменте кода урока пропущены два ключевых элемента. Впишите оба пропущенных значения через запятую в порядке появления (например: x, 5).

class _____
{
    public string Name { get;}
    public Person(string name) => Name=name;
}
class Company
{
    Person[] _____;
    public Company(Person[] people) => personal = people;
    // индексатор
    public Person this[int index]
    {
        get => personal[index];
        set => personal[index] = value;
    }
}
Войдите, чтобы отправить решение
Среднее Ручная проверка Расставьте строки кода в правильном порядке
+20 XP

Строки кода из примера этого урока перемешаны. Впишите их в правильном порядке, каждую строку — с новой строки.

{
	set { ... }
возвращаемый_тип this [Тип параметр1, ...]
}
	get { ... }
Войдите, чтобы отправить решение
Сложное Ручная проверка Объясните и модифицируйте пример из урока «Индексаторы»
+30 XP

Опишите своими словами, что делает приведённый пример кода из урока «Индексаторы», и предложите одно осмысленное изменение (например, другое входное значение или дополнительное условие). Приведите итоговый код.

возвращаемый_тип this [Тип параметр1, ...]
{
	get { ... }
	set { ... }
}
Войдите, чтобы отправить решение
Сложное Ручная проверка Найдите потенциальную проблему в коде урока «Индексаторы»
+30 XP

Изучите приведённый фрагмент кода и опишите, при каких входных данных или условиях он может сработать не так, как ожидается (граничный случай, отсутствие проверки и т.п.). Предложите исправленный вариант.

class Person
{
    public string Name { get;}
    public Person(string name) => Name=name;
}
class Company
{
    Person[] personal;
    public Company(Person[] people) => personal = people;
    // индексатор
    public Person this[int index]
    {
        get => personal[index];
        set => personal[index] = value;
    }
}
Войдите, чтобы отправить решение
Мини-проект Ручная проверка Мини-проект по теме «Индексаторы»
+50 XP

Соберите небольшую программу, которая последовательно демонстрирует ключевые идеи урока. Программа должна быть рабочей и содержать минимум два самостоятельно написанных фрагмента, а не просто копию примера из урока.

Войдите, чтобы отправить решение
Домашнее задание Ручная проверка Домашнее задание по теме «Индексаторы»
+25 XP

Напишите собственную небольшую программу, применяющую материал темы «Индексаторы». Используйте не менее одной конструкции, показанной в примерах урока. Прикрепите код решения и краткое описание того, что он делает.

Войдите, чтобы отправить решение

Обсуждение (0)

Войдите, чтобы оставить комментарий.