
- •Стандартные интерфейсы. Клонирование. Итераторы Стандартные интерфейсы .Net
- •Сравнение объектов (интерфейс iComparable)
- •Пример использования стандартного интерфейса iComparable на примере класса Monster
- •Сортировка объектов по различным критериям (интерфейс iComparer)
- •Пример использования стандартного интерфейса iComparer на примере класса Monster
- •Int сила, умение;
- •Клонирование объектов (интерфейс iCloneable)
- •Int сила, умение;
- •Перебор элементов (интерфейс iEnumerable) и итераторы
- •Пример работы класса с итератором
- •Int сила, умение;
- •Примеры применения простейших итераторов
Клонирование объектов (интерфейс 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.