Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Стандартные интерфейсы. Клонирование.Итераторы.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
123.39 Кб
Скачать

Клонирование объектов (интерфейс iCloneable)

Клонирование-создание копии объекта. Копия объекта называется клоном. При присваивании одного экземпляра другому копируется ссылка, а не сам объект. Если необходимо скопировать в другую область памяти поля объекта, можно воспользоваться методом MemberwiseClone(), который любой объект наследует от класса object. При этом объекты, на которые указывают поля объекта, в свою очередь являющиеся ссылками, не копируются. Это называется поверхностным клонированием. Для создания полностью независимых объектов необходимо глубокое копирование, когда в памяти создается дубликат всего дерева объектов, то есть объектов, на которые ссылаются поля объекта, поля полей, и т.д. Алгоритм глубокого копирования сложен, требует рекурсивного обхода всех ссылок объекта и отслеживания циклических зависимостей.

Объект, имеющий собственные алгоритмы клонирования, должен объявляться как производный интерфейса ICloneable и переопределять его единственный метод Clone().

Модернизируем предыдущий пример и создадим поверхностную копию экземпляра класса Monster с помощью метода MemberwiseClone() и реализации интерфейса ICloneable. Метод MemberwiseClone() можно вызывать только из методов класса, так как он объявлен в классе object как protected.

using System;

using System.Collections;

using System.Linq;

using System.Text;

namespace ConsoleApplication1

{

class Monster :ICloneable

{

public Monster(int сила, int умение, string имя)

{

this.сила = сила;

this.умение = умение;

this.имя = имя;

}

public Monster ShallowClone()

{

return (Monster)this.MemberwiseClone();

}

public object Clone()

{

return new Monster(this.сила, this.умение, "Это-клон!" + this.имя);

}

public int Умение

{

get { return умение; }

set

{

if (value > 0) умение = value;

else умение = 0;

}

}

public void Passport()

{

Console.WriteLine("Монстр {0} сила = {1} умение= {2}", имя, сила, умение);

}

string имя;

Int сила, умение;

}

class Program

{

static void Main(string[] args)

{ Monster Вася=new Monster (100,100,"Вася");

Monster X = Вася;

//2 способа создания клонов – метод ShallowClone() и Clone()

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

Monster Z = (Monster)Вася.Clone();

Чем отличается

Вася.Passport();

X.Passport();

Y.Passport();

Z.Passport();

Console.ReadLine(); } }}

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

Перебор элементов (интерфейс iEnumerable) и итераторы

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

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

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

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

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

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

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

Таким образом, для того, чтобы применить цикл foreach необходимо реализовать четыре метода GetEnumerator(), Current, MoveNext() и Reset().

Например, если элементы класса организованы как массив, необходимо описать закрытое поле класса, хранящее текущий индекс в массиве, в методе MoveNext() задать изменение этого индекса на 1 и проверку выхода за границу массива, а в свойстве Current – возврат элемента массива по текущему индексу.

В языке С# имеются стандартные средства, обеспечивающие аналогичные действия, которые выполняют перебор элементов в объекте – итераторы.

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