Что такое индексатор в C# и как сделать обращение к объекту через квадратные скобки?
Хочу, чтобы к моему классу-обёртке над массивом можно было обращаться как obj[0], а не obj.Get(0). Видел, что для этого есть «индексаторы». Как это работает и при чём тут get/set?
var week = new Week();
string d = week[0]; // хочу так
2 ответа
Индексатор — это специальное свойство, которое позволяет обращаться к объекту через [], как к массиву. Объявляется ключевым словом this с параметром в квадратных скобках, и внутри у него есть get/set — как у обычных свойств.
class Week
{
private string[] days =
{ "Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс" };
public string this[int index]
{
get => days[index];
set => days[index] = value; // value — переданное значение
}
}
var week = new Week();
Console.WriteLine(week[0]); // Пн
week[0] = "Понедельник"; // сработает set
Console.WriteLine(week[0]); // Понедельник
Индекс не обязан быть int — можно сделать доступ по строке, как у словаря:
class Settings
{
private Dictionary<string, string> data = new();
public string this[string key]
{
get => data.TryGetValue(key, out var v) ? v : "";
set => data[key] = value;
}
}
var s = new Settings();
s["theme"] = "dark";
Console.WriteLine(s["theme"]); // dark
Индексаторы можно перегружать (разные типы индекса) и делать с одним только get (доступ только на чтение). Именно так устроены List<T> и Dictionary<K,V> внутри.
Имейте в виду: в индексаторе вы сами отвечаете за проверку границ. Если просто пробросить во внутренний массив, при выходе за диапазон полетит IndexOutOfRangeException. Лучше проверять явно:
public string this[int index]
{
get
{
if (index < 0 || index >= days.Length)
throw new ArgumentOutOfRangeException(nameof(index));
return days[index];
}
}
И не делайте индексатор тяжёлым по вычислениям — синтаксис obj[i] создаёт у читателя ожидание, что это дёшево, как доступ к массиву.