Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
7 семестр / Учебники / Все лекции С# / Все лекции С# / Лекция 17. Семейства. Индексаторы.doc
Скачиваний:
132
Добавлен:
24.02.2016
Размер:
121.34 Кб
Скачать

Определение собственных семейств

Программист может создавать собственные строго типизированные семейства. Один из способов — это реализовать все необходимые методы вручную, однако такой подход может потребовать очень больших затрат времени, а в некоторых случаях оказаться чрезвычайно сложным. В качестве альтернативы существует возможность создать семейство, являющееся производным от некоторого класса, например, от System.Collections.CollectionBase — абстрактного класса, в котором реализована большая часть семейств.

Класс CollectionBaseпредоставляет интерфейсыIEnumerable,ICollectionиIList, однако в них реализованы только некоторые из необходимых методов. Если возникает необходимость в каких-либо дополнительных функциональных возможностях, то их приходится реализовывать самостоятельно. Для этого в классе CollectionBase предусмотрено два защищенных свойства, которые позволяют осуществлять доступ собственно к хранящимся объектам. Можно воспользоваться свойством List — оно обеспечивает доступ к элементам посредством интерфейсаIList, и свойствомInnerList — оно является объектом ArrayList и используется для хранения элементов.

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

public class Animals : CollectionBase

{

public void Add(Animal newAnimal)

{List.Add(newAnimal);}

public void Remove(Animal oldAnimal)

{

List.Remove(oldAnimal);

}

publicAnimals(){}

}

В данном случае Add() и Remove() реализованы как строго типизированные методы, которые используют стандартный метод Add() интерфейса IList для осуществления доступа к элементам. Представленные методы будут работатьтолько с классами Animal или с классами, производными от Animal, в отличие от реализованного ранее примера с ArrayList, которые допускали использованиепроизвольныхобъектов. Класс CollectionBase позволяет использовать foreach для производных семейств. Можно, например, написать следующий код:

Console.WriteLine("Использование семейства дляclassAnimals:");

Animals animalCollection = new Animals();

animalCollection. Add(newCow("Новая Буренка"));

foreach (Animal myAnimal in animalCollection)

{

Console.WriteLine("Новый {0} объект добавлен в семейство” + "Name = {1}”, myAnimal.ToString(), myAnimal.Name);

}

А вот этот код является недопустимым:

animalCollection[0].Feed();

Для того чтобы осуществлять доступ к элементам по их индексам таким способом, придется воспользоваться индексатором (indexer).

Индексаторы

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

Индексатор (indexer) в C# является конструкцией, позволяющей программисту пользоваться привычным синтаксисом с квадратными скобками для обращения к объектам классов коллекций, являющихся членами класса.

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

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

спецификаторы тип_возвращ_значения this [список_параметров]

{

get код_доступа

set код_доступа

}

Код доступа представляет собой блоки операторов, которые выполняются при получении (get) или установки (set) значения элемента массива. Если отсутствует частьset, индексатор доступен только для чтения (readonly), если отсутствует частьget, то индексатор доступен только для записи (writeonly).

Список параметров содержит описание индексов, по которым выполняется доступ к элементу. Чаще всего это целочисленный индекс.

В предыдущем примере можно добавить индексатор в семейство Animals объектов Animal следующим образом:

public class Animals : CollectionBase

{…

//здесь Animal- тип индексатора. Это тот тип, который будет получаться при //обращении к элементу посредством данного индексатора

public Animal this[int animalIndex] //Индексаторособое свойство

{

get

{

return (Animal)List[animalIndex]; //явное приведение типа, так как List //возвращает объект класса System.Object

}

set

{

List[animalIndex] =value;

}

}

}

Ключевое слово this используется с параметрами, задаваемыми в квадратных скобках, однако во всем остальном оно выглядит почти точно так же, как и любое другое свойство. Такой синтаксис представляется весьма логичным, поскольку осуществляется доступ к индексатору, используя имя объекта, за которым следует один или несколько параметров, заключенных в квадратные скобки (например, MyAnimals[0]).

Возвращаемый тип определяет тип объекта, возвращаемого индексатором, а тип аргумента определяет, какие аргументы будут задействованы для индексации объекта класса коллекции, содержащего требуемые объекты. Хотя общепринято использовать в качестве индексов целые числа, допустимо индексировать объекты классов коллекций аргументами другого типа, например строками. Более того, можно указать несколько аргументов, создав тем самым многомерный массив! Ключевое слово this - это ссылка на объект, в котором появляется индексатор. Как и в случае обычного свойства, необходимо определить методы get() и set(), описывающие, как запрошенный объект будет извлекаться из объекта класса коллекции или записываться в него.