На примере, рассмотренном выше, вы убедились в том, что при использовании метода ToArray по умолчанию происходит поверхностное (shallow) копирование. Следующий фрагмент убедит вас в том, что и метод Clone, имеющийся в классе ArrayList, тоже поизводит мелкое копирование. Что же надо сделать, чтобы создать настоящую копию коллекции (deep copy) и, таким образом, отвязать ее от коллекции-источника копирования? Документация говорит, что для этого надо в классе пользовательских объектов явно реализовать интерфейс ICloneable. Для нас это означает следующее. Надо добавить к списку родителей класса Man интерфейс ICloneable и, кроме того, ввести в класс явную реализацию метода Clone. Сделайте это.
public class Man : IComparable, ICloneable // Теперь класс реализует два интерфейса
object ICloneable.Clone() // Явная реализация метода интерфейса
{
return // Создаем и возвращаем новый объект в виде копии существующего (Ваш код . . .)
}
Убедитесь, что это работает с помощью следующего, несколько вычурного, кода:
Man ken = new Man("Ken Wood",40);
ArrayList men = new ArrayList(); // Создаем коллекцию
men.Add (ken); men.Add (ken);
ma = new Man[men.Count]; // Создаем новый массив заданного размера
for (int i=0; i<men.Count; i++) // Делаем копию, требующую много приведений типов
ma[i] = (Man)((ICloneable)(Man)men[i]).Clone();
Console.WriteLine ("\nClone array of men:\n");
foreach (Man m in ma)
m.Out();
Console.WriteLine ("\nChanging source men[0]");
men[0].In(); // Пытаемся изменить оригинал и проверить копию
Console.WriteLine ("\nTest the target: ma[0] = {0}", ma[0]);
Вы обратили внимание на двойное приведение типа? Именно такой стиль работает при явной (explicit) реализации интерфейса. Проверка показывает, что мы добились желаемого, но возможен и другой, более простой подход:
· Введите в класс Man конструктор копирования:
public Man (Man m) { name = m.name; age = m.age; }
Затем вместо того, чтобы переопределять непосредственно ICloneable.Clone:
object ICloneable.Clone() { . . . } // Так было ранее
· Дайте другую (неявную, или implicit) версию (унаследованного от интерфейса ICloneable) метода Clone.
public object Clone() { return new Man(this); }
Теперь клонирование всей коллекции выглядит проще.
object[] mo = new Man[men.Count];
for (int i=0; i<men.Count; i++)// Делаем копию, требующую одно приведение типов
mo[i] = ((Man)men[i]).Clone();
Но это неблагодарный труд, так как методы CopyTo (и ToArray) не изменили своего поведения по отношению к классу Man, они по-прежнему делают копии ссылок. Введение конструктора копирования также не изменило поведения методов CopyTo и ToArray, но сделало возможным почленное копирование коллекции обычным способом.
object[] mo = new Man[men.Count]; int i =0;
foreach (Man m in men)
mo[i++] = new Man (m);
Знание техники работы с интерфейсами, а также осведомленность о множестве существующих интерфейсов (уже реализованных классами библиотеки .NET) позволяет понять особенности функционирования новых видов коллекций. Все они реализуют тот или иной набор стандартных интерфейсов. Например, все массивы в .NET считаются наследниками класса System.Array:
public abstract class Array : ICloneable, IList, ICollection, IEnumerable
На самом деле мы не можем создать класс, производный от Array, но система гарантирует, что все методы, объявленные в нем, реализованы в массивах объектов любых типов. Именно по этой причине мы имели возможность пользоваться методами: GetLength, GetValue, CopyTo, а также свойствами: Rank, Length. Итак, массивы поддерживают идею наследования ООП, но не позволяют вмешиваться и переопределять методы и свойства. Это сделано с целью поддержки высокой эффективности работы с данными.
Этот класс иногда называют ассоциативным массивом. Он реализует функциональность коллекции пар, каждая из которых состоит из ключа (key) и ассоциированного с ним значения (value). Например, пара может состоять из имени и номера телефона: (string name, string phone). Здесь роль ключа выполняет строка символов name (объект класса string), а значением является другая строка — номер телефона.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.