ТОР 5 статей: Методические подходы к анализу финансового состояния предприятия Проблема периодизации русской литературы ХХ века. Краткая характеристика второй половины ХХ века Характеристика шлифовальных кругов и ее маркировка Служебные части речи. Предлог. Союз. Частицы КАТЕГОРИИ:
|
Интерфейс IEnumeratorИтераторы и контейнеры со встроенным методом GetEnumerator позволяют достаточно просто организовать перечислимость объектов класса, позволяя клиентам класса использовать цикл foreach для доступа к объектам на чтение. В основе предоставляемого механизма доступа лежат методы интерфейса IEnumerator. Используя итератор или встроенный метод GetEnumerator, можно не вникать в суть того, как, например, метод GetEnumerator создает объект интерфейса IEnumerator. Тем не менее в ряде случаев полезно при организации перечислимости объектов класса объявить класс наследником интерфейса IEnumerator и реализовать самостоятельно методы этого интерфейса. Реализация в классе свойств и методов этого интерфейса позволяет клиентам класса самостоятельно организовать работу с объектами класса как с коллекцией. Обычно это не делается, а используются возможности, предоставляемые циклом for each, который скрывает детали применения свойств и методов интерфейса. Общая схема перечисления объектов в коллекции такова. Коллекция рассматривается как список с курсором. Вводится понятие позиции курсора, указывающей на текущий объект из списка. В начальный момент курсор установлен перед первым объектом списка и текущий объект не определен. Курсор можно передвигать к следующему элементу списка. Можно прочесть значение элемента, на который указывает курсор. Методы интерфейса IEnumerator позволяют реализовать такую схему работы с коллекцией объектов. Если методы интерфейса предполагается сделать доступными для клиентов, то они реализуются как открытые методы. Метод bool MoveNext () передвигает курсор к следующему элементу списка, так что после его первого вызова курсор будет указывать на первый элемент списка. После его вызова, когда курсор указывает на последний элемент списка, текущий элемент снова становится неопределенным, а позиция курсора смещается за последний элемент. Метод MoveNext возвращает значение true, когда курсор указывает на элемент списка, и возвращает false, когда курсор вне списка элементов. Метод void Reset() возвращает курсор в начальную позицию перед первым элементом списка. Метод-свойство Object Current { get } возвращает текущий элемент списка. Выбрасывается исключение InvalidOperationException,если при вызове свойства Current курсор установлен перед или после списка элементов. Приведу теперь пример класса, реализующего интерфейс IEnumerator. Давайте построим класс People, который будет наследником класса Persons и интерфейса IEnumerator. Будучи наследником класса Persons, новый класс будет обладать всеми возможностями родительского класса, в том числе перечислимостью объектов. Но как наследник интерфейса IEnumerator он реализует методы интерфейса и предоставит своим клиентам новые возможности. /// <summary> /// Наследник класса Persons /// Реализует методы интерфейса IEnumerator /// Предоставляет клиентам класса возможность /// собственной организации перебора объектов /// </summary> class People:Persons,IEnumerator { int position = -1; public People(): base() { } public People(int size): base(size) { } public People(Person[] people): base(people) { }
/// <summary> /// Передвигает курсор к следующему элементу в контейнере /// Возвращает true, если курсор установлен на элементе списка, /// false - в противном случае /// </summary> /// <returns></returns> public bool MoveNext() { if (position < size) position++; return (position < size); } /// <summary> /// Восстанавливает текущее положение курсора /// в контейнере объектов /// </summary> public void Reset() { position = -1; } /// <summary> /// Возвращает текущий объект, если курсор установлен /// на элементе списка /// Выбрасывает исключение InvalidOperationException, /// когда курсор вне списка /// </summary> public object Current { get { try { return container[position]; }
catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } set { try { container[position] = (Person)value; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } У класса три собственных конструктора, которые сводятся к вызову конструкторов родителя, поле position, необходимое для организации доступа, и три открытых метода, реализующих методы интерфейса IEnumerator. Методы устроены достаточно просто и в особых комментариях не нуждаются. Но стоит обратить внимание на реализацию метода-свойства Current. В самом интерфейсе для этого свойства указан только метод get. В реализации я добавил и реализацию метода set. Это сразу же расширяет возможности клиента. Если при работе с методом foreach объекты доступны только для чтения, то теперь свойство Current позволяет изменять элементы коллекции. Тест, построенный для работы с новым классом People, демонстрирует все эти возможности. public void TestPeople() { People people = new People(); foreach (Person person in people) Console.WriteLine(person.ToString());
Console.WriteLine("Работа клиента с коллекцией!"); try { Person person; person = new Person("James Bond", 44); people.MoveNext(); people.Current = person; people.Reset(); while (true) { people.MoveNext(); person = (Person)people.Current; Console.WriteLine(person.ToString()); } } catch (InvalidOperationException) { people.Reset(); } } Результаты работы этого теста показаны на рис. 5.10. Рис. 5.10. Реализация интерфейса IEnumerator Обратите внимание: клиент сумел изменить объект, полученный в результате перечисления, добавив "Джеймса Бонда" в список агентов. На этой оптимистической ноте закончим тему организации перечислимости в классе. Не нашли, что искали? Воспользуйтесь поиском:
|