Создание пользовательских индексаторов

We use cookies. Read the Privacy and Cookie Policy

Создание пользовательских индексаторов

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

// Объявление массива целых значений.

int[] myInts = {10, 9, 100, 432, 9874};

// Использование операции [] для доступа к элементам.

for (int j = 0; j ‹ myInts.Length; j++) Console.WriteLine("Индекс {0} = {1}", j, myInts[j]);

Этот программный код ни в коем случае не претендует на новизну. Но язык C# дает возможность строить пользовательские классы и структуры, которые могут индексироваться подобно стандартным массивам. Поэтому совсем не удивительно, что метод, который обеспечивает такой доступ к элементам, называется индекса-mopoм.

Перед тем как приступить к созданию соответствующей конструкции, мы рассмотрим один пример. Предположим, что поддержка метода индексатора уже добавлена в пользовательскую коллекцию Garage (гараж), уже рассматривавшуюся в главе 8. Проанализируйте следующий пример ее использования.

// Индексаторы обеспечивают доступ к элементам подобно массивам.

public class Program {

 static void Main(string[] args) {

  Console.WriteLine("***** Забавы с индексаторами ***** ");

  // Предположим, что Garage имеет метод индексатора.

  Garage carLot = new Garage();

  // Добавление в гараж машин с помощью индексатора.

  сarLot[0] = new Саr("FееFee", 200);

  carLot[1] = new Car("Clunker", 90);

  carLot[2] = new Car("Zippy", 30);

  // Чтение и отображение элементов с помощью индексатора.

  for (int i = 0; i ‹ 3; i++) {

   Console.WriteLine("Hомep машины: {0}", i);

   Console.WriteLite("Нaзвaниe: {0}", carLot[i].PetName);

   Console.WriteLine("Максимальная скорость: {0}", carLot[i].CurrSpeed);

   Console.WriteLine();

  }

  Console.ReadLine();

 }

}

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

Здесь возникает вопрос: "Как сконфигурировать класс (или структуру), чтобы обеспечить поддержку соответствующих функциональных возможностей?" Индексатор в C# представляет собой несколько "искаженное" свойство. Для создания индексатора в самой простой форме используется синтаксис this[]. Вот как может выглядеть подходящая модификации типа Garage.

// Добавление индексатора в определение класса.

public class Garage: IEnumerable { // для каждого элемента

 …

 // Использование ArrayList для типов Car.

 private ArrayList carArray = new ArrayList();

 // Индексатор возвращает тип Car, соответствующий

 // Числовому индексу.

 public Car this[int pos] {

  // ArrayList тоже имеет индексатор!

  get { return (Car)carArray[pos]; }

  set { carArray.Add(value); }

 }

}

Если не обращать внимания на ключевое слово this, то объявление индексатора очень похоже на объявление свойства в C#. Но следует подчеркнуть, что индексаторы не обеспечивают иных функциональных возможностей массива, кроме возможности использования операции индексирования, Другими словами, пользователь объекта не может применить программный код, подобный следующему.

// Используется свойство ArrayList.Count? Нет!

Console.WriteLine("Машин в наличии: {0} ", carLot.Count);

Для поддержки этой функциональной возможности вы должны добавить свое свойство Count в тип Garage и, соответственно, делегат.

public class Garage: IEnumerable {

 …

 // Локализация/делегирование в действии снова.

 public int Count { get { return carArray.Count; } }

}

Итак, индексаторы – это еще одна синтаксическая "конфетка", поскольку соответствующих функциональных возможностей можно достичь и с помощью "обычных" методов. Например, если бы тип Garage не поддерживал индексатор, все равно можно было бы позволить "внешнему миру" взаимодействовать с внутренним массивом, используя для этого именованное свойство или традиционные методы чтения и модификации данных (accessor/mutator). Но при использовании индексаторов пользовательские типы коллекции лучше согласуются со структурой библиотек базовых классов .NET.

Исходный код. Проект SimpleIndexer размещен в подкаталоге, соответствующем главе 9.