Программирование >>  Обработка исключительных ситуаций 

1 ... 32 33 34 [ 35 ] 36 37 38 ... 142


Для создания полностью независимых объектов необходимо глубокое клонирование, когда в памяти создается дубликат всего дерева объектов, то есть объектов, на которые ссылаются поля объекта, поля полей и т. д. (рис. 9.1, в). Алгоритм глубокого клонирования весьма сложен, поскольку требует рекурсивного обхода всех ссылок объекта и отслеживания циклических зависимостей.

Объект, имеющий собственные алгоритмы клонирования, должен объявляться как наследник интерфейса ICloneable и переопределять его единственный метод С1огт В листинге 9.4 приведен пример создания поверхностной копии объекта класса Monster с помощью метода MemberwiseClone, а также реализован интерфейс ICloneabr В демонстрационных целях в имя клона объекта добавлено слово Клон .

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

Листинг 9.4. Клонирование объектов using System:

namespace ConsoleApplIcationi

class Monster : ICloneable

public Monster( int health, int ammo, string name )

this.health = health: this.ammo = ammo: this.name = name;

public Monster ShallowClone() поверхностная копия

return (Monster)this,MemberwiseClone();

public object CloneO пользовательская копия

return new Monster( this.health, this.ammo. Клон + this.name );

virtual public void PassportO

Console.WriteLineC Monster {0} \t health = {1} ammo = {2} , name, health, ammo );

string name;

int health, ammo;

class Classl

{ static void MainO



Объект X ссылается на ту же область памяти, что и объект Вася. Следовательно, если мы внесем изменения в один из этих объектов, это отразится на другом. Объекты Y и Z, созданные путем клонирования, обладают собственными копиями значений полей и независимы от исходного объекта.

Перебор объектов (интерфейс I Enumerable) и итераторы

Оператор foreach является удобным средством перебора элементов объекта. Массивы и все стандартные коллекции библиотеки .NET позволяют выполнять такой перебор благодаря тому, что в них реализованы интерфейсы lEnumerable и lEnumerator. Для применения оператора foreach к пользовательскому типу данных требуется реализовать в нем эти интерфейсы. Давайте посмотрим, как это делается.

Интерфейс lEnumerable (перечислимый) определяет всего один метод - GetEnuraerator, возвращающий объект типа lEnumerator (перечислитель), который можно исполь зовать для просмотра элементов объекта.

Интерфейс IEnumerator задает три элемента:

свойство Current, возвращающее текущий элемент объекта;

метод MoveNext, продвигающий перечислитель на следующий элемент объекта;

метод Reset, устанавливающий перечислитель в начало просмотра.

Цикл foreach использует эти методы для перебора элементов, из которых состоит объект.

Таким образом, если требуется, чтобы для перебора элементов класса мог применяться цикл foreach, необходимо реализовать четыре метода: GetEnumerator, Current, MoveNext и Reset. Например, если внутренние элементы класса организованы в массив, потребуется описать закрытое поле класса, хранящее текущий индекс в массиве, в методе MoveNext задать изменение этого индекса на 1 с проверкой выхода за границу массива, в методе Current - возврат элемента массива по текущему индексу и т. д.

Это не интересная работа, а выполнять ее приходится часто, поэтому в версию 2.0 были введены средства, облетающие выполнение перебора в объекте - итераторы.

Итератор представляет собой блок кода, задающий последовательность перебора элементов объекта. На каждом проходе цикла foreach выполняется один шаг

Monster Вася = new Monster( 70. 80. Вася );

Monster X = Вася;

Monster Y = Вася.ShallowClone();

Monster Z = (Моп51ег)Вася.CIone();



class Classl

{ static void MainO

Stado s = new StadoO; s.Add( new Monster() ); s.Add( new Monster( Вася ) ): s.Add( new Daemon О );

foreach ( Monster m in s ) m.Passport();

итератора, заканчивающийся выдачей очередного значения. Выдача значения выполняется с помощью ключевого слова yield.

Рассмотрим создание итератора на примере (листинг 9.5). Пусть требуется создать объект, содержащий боевую группу экземпляров типа Monster, неоднократно использованного в примерах этой книги. Для простоты ограничим максимальное количество бойцов в группе десятью.

Листинг9.5. Класс с итератором

using System;

using System.Col lections;

namespace ConsoleApplicationi

class Monster { ... }

class Daemon { ... }

class Stado ; IEnumerable 1

private Monster[] mas; private int n;

public StadoO

mas = new Monster[10]; n = 0;

public lEnumerator GetEnumeratoK)

for ( int i = 0; i < n; ++i ) yield return mas[i]; 2

public void Add( Monster m )

if ( n >= 10 ) return; mas[n] = m:

++n;



1 ... 32 33 34 [ 35 ] 36 37 38 ... 142

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика