Как работать с индексаторами на C #

Язык программирования C # включает поддержку индексаторов - функцию, которая позволяет использовать объект просто как массив. Индексаторы также известны как интеллектуальные массивы и могут быть определены аналогично тому, как определяется свойство. В MSDN говорится: «Индексаторы позволяют индексировать экземпляры класса или структуры так же, как массивы. Индексаторы похожи на свойства, за исключением того, что их методы доступа принимают параметры».

Хотя индексаторы и свойства имеют много общего, между ними есть тонкие различия. В отличие от свойств, вы можете получить доступ к индексатору с помощью индексов. Помните, что вам нужно получить доступ к свойству, используя его имя. Кроме того, индексаторы являются членами экземпляра класса и, следовательно, не могут быть статическими. У вас могут быть как статические, так и нестатические свойства.

В следующем фрагменте кода показано, как объявляется индексатор:

this [argument list]

{

  get

  {

  }

  Set

  {

  }

}

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

Рассмотрим следующий класс:

public class Contact

    {

        private string[] address = new string[3];

        public string this[int index]

        {

            get

            {

                return address[index];

            }

            set

            {

                address[index] = value;

            }

        }

    }

Класс Contact содержит частный член с именем address и определяет индексатор. Член адреса - это массив строкового типа. Вот как вы можете создать экземпляр класса Contact и использовать индексатор.

Contact contact = new Contact();

 contact[0] = "Begumpet";

 contact[1] = "Hyderabad";

 contact[2] = "Telengana";

for (int i = 0; i < 3; i++)

Console.WriteLine (contact[i]);

Следует отметить, что для определения индексаторов необходимо использовать ключевое слово this. Обратите внимание, что вы не ограничены использованием только целых чисел в качестве индексов для доступа к индексаторам - вы даже можете использовать другие механизмы поиска. Индексатор обычно используется, когда ваш класс представляет коллекцию или объекты. Затем вы можете использовать индексатор для доступа к определенному элементу с помощью index.

Попробуем на примере. Рассмотрим следующий класс с именем Customer.

public class Customer

    {

       public List Orders

        {

            get; set;

        }

       public Order this[int orderID]

        {

            get

            {

                return (from o in Orders

                        where o.OrderID == orderID

                        select o).First();

            }

        }

    }

Класс Customer определяет индексатор типа Order. Он также содержит общедоступное свойство, которое представляет собой список типа Order. Вот класс Order для вашей справки.

public class Order

    {

        public int OrderID

        {

            get; set;

        }

    }

В следующем фрагменте кода показано, как получить доступ к индексатору класса Customer для получения определенного заказа.

   List lstOrder = new List();

  Order o1 = new Order();

  o1.OrderID = 1;

  Order o2 = new Order();

  o2.OrderID = 2;           

  lstOrder.Add(o1);

  lstOrder.Add(o2);

  Customer customer = new Customer();

  customer.Orders = lstOrder;

  Order o = customer[1];

См. Фрагмент кода выше. Обратите внимание, как был создан общий список типа Order и назначен свойству Orders экземпляра класса Customer. Затем вы просто передаете OrderId в качестве параметра для получения конкретного экземпляра заказа.

Индексаторы поддерживают наследование, могут быть полиморфными, а также могут быть абстрактными. Рассмотрим следующий класс, который определяет виртуальный индексатор. Класс ContactBase - это модифицированная версия класса Contact, о котором мы говорили ранее в этой статье.

 public class ContactBase

    {

        protected string[] address = new string[3];

        public virtual string this[int index]

        {

            get

            {

                return address[index];

            }

            set

            {

                address[index] = value;

            }

        }

    }

Теперь вы можете унаследовать класс от класса ContactBase и переопределить индексатор, как показано ниже.

public class ConcreteContact: ContactBase

    {

       public override string this[int index]

        {

            get

            {

                return address[index];

            }

            set

            {

                address[index] = value;

            }

        }

    }

Итак, в приведенном выше примере кода мы исследовали, как можно использовать индексаторы при наследовании типов и как они могут демонстрировать полиморфное поведение.

Вы также можете определить индексатор как абстрактный. Для этого вам нужно создать абстрактный класс, а затем определить индексатор как абстрактный внутри него. Давайте изменим класс ContactBase и определим индексатор как абстрактный. Вот как теперь будет выглядеть измененная версия класса ContactBase:

 public abstract class ContactBase

    {

        protected string[] address = new string[3];

        public abstract string this[int index]

        {

            get; set;

        }

}

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

ConcreteContact contact = new ConcreteContact();

contact[0] = "Begumpet";

contact[1] = "Hyderabad";

contact[2] = "Telengana";