Индексаторы C#

Добрый день дорогие подписчики. Сегодня мы поговорим про индексаторы C#, рассмотрим с вами, что это такое, какие особенности они имеют, как они реализованы в C# и конечно же разберем как с ними работать.

Подпишись на группу Вконтакте и Телеграм-канал. Там еще больше полезного контента для программистов.
А на YouTube-канале ты найдешь обучающие видео по программированию. Подписывайся!

Индексаторы

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

Индексаторы — это члены класса, которые позволяют получить доступ к полям класса аналогичным способом доступа как к элементам массива, т.е. по индексу.

Синтаксис индексатора

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

Как видим от свойств индексатор отличается отсутствием имени. Для замены имени используется ключевое слово this далее в квадратных скобках идет набор параметров с их типом. Обязательное условие индексатор должен иметь минимум один параметр. Давайте рассмотрим пример использования индексаторов. Создадим два класса Parking и Car. У класса Car объявим набор свойств.

Класс Parking

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace lesson22
{
  class Parking
  {
     private List<Car> _cars = new List<Car>();
     private const int MAX_CARS = 100;
 
     public Car this[string number]
     {
        get
        {
          var car = _cars.FirstOrDefault(c => c.Number == number);
          return car;
        }    
      }
 
      public int Count => _cars.Count;
 
      public string Name { get; set; }
 
      public int Add(Car car)
      {
        if (car == null)
        {
          throw new ArgumentNullException(nameof(car), "Car is null");
         }
 
         if (_cars.Count < MAX_CARS)
         {
            _cars.Add(car);
            return _cars.Count - 1;
          }
          return -1;
         }
 
        public void GoOut(string number)
        {
          if (string.IsNullOrWhiteSpace(number))
          {
            throw new ArgumentNullException(nameof(number), "Number is null or empty.");
           }
 
           var car = _cars.FirstOrDefault(c => c.Number == number); 
 
           if(car != null)
           {
              _cars.Remove(car);
           }
        }
    }
}

Класс Car




using System;
 
 
namespace lesson22
{
    class Car
    {
        public string Name { get; set; }
 
        public string Number { get; set; }
 
        public override string ToString()
        {
            return Name + " " + Number;
        }
    }
}

Создадим несколько экземпляров класса Car и новый экземпляр класса Parking

var cars = new List<Car>()
            {
                new Car() {Name = "Ford", Number = "A001AA01"},
                new Car() {Name = "Lada", Number = "B727ET77"},
            };
var parking = new Parking();

Обратимся к parking при помощи индексатора :

Console.WriteLine(parking["A001AA01"]?.Name);
Console.WriteLine(parking["A001AA02"]?.Name);

В результате наша программа выдаст ответ:

Результат работы индексатора

Как мы можем видеть обращение:

Console.WriteLine(parking["A001AA02"]?.Name);

не обрабатывается, это связано с тем что у нас нет экземпляра с значение параметра Number = «A001AA02»

Подробный разбор данного примера Вы можете посмотреть на нашем YouTube канале по ссылке, кроме этого исходный код всех примеров можно скопировать в GitHub профиле.

Индексаторы с несколькими параметрами

Рассмотрим ситуацию когда нам необходимо использовать несколько параметров при создание интексатора.

public Car this[string number, string id]
 {
 get
 {
 var car = _cars.FirstOrDefault(c => c.Number == number && c.Id == id);
 return car;
 }
 }

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

var cars = new List<Car>()
{
   new Car() {Name = "Ford", Number = "A001AA01", Id = "001" },
   new Car() {Name = "Lada", Number = "B727ET77", Id = "002" },
}

Создавая обращение нам теперь необходимо указывать два параметра

Console.WriteLine(parking["A001AA01","001"]?.Name);
Console.WriteLine(parking["B727ET77", "003"]?.Name);

Как мы можем увидеть у нас допущенна ошибка во второй строке и поэтому программа нам выдаст сообветствующий ответ

Результат работы индексатора

Общие данные об индексаторах:

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

Сравнение индексатора и свойства

Данные взяты на основе сайта docs.microsoft.com

Свойство.

Позволяет вызывать методы как открытые члены данных.

Доступ по простому имени.

Может быть статическим членом или членом экземпляра.

Метод доступа get свойства не имеет параметров.


Метод доступа set свойства содержит неявный параметр value.


Поддерживает сокращенный синтаксис с использованием автоматически реализуемых свойств.

Индексатор

Обеспечивает доступ к элементам внутренней коллекции объекта с использованием нотации массива для самого объекта.

Доступ посредством индекса

Должен быть членом экземпляра.

Метод доступа get индексатора имеет тот же список формальных параметров, что и сам индексатор.

Метод доступа set индексатора имеет тот же список формальных параметров, что и сам индексатор, и также должен содержать параметр value.

Поддерживает элементы в виде выражения для индексаторов только для получения.

Советую прочитать предыдущую статью — Советы по составлению расписания для программистов
А также подписывайтесь на группу ВКонтактеTelegramИнстаграм и YouTube-канал. Там еще больше полезного и интересного для программистов.