Программирование >>  Программирование с использованием ajax 

1 ... 94 95 96 [ 97 ] 98 99 100 ... 396


Для получения желаемого поведения в этот код можно добавить следующий простой итератор:

public new lEnumerator GetEnumerator () {

foreach (object animal in Dictionary.Values) yield return (Animal)animal;

Теперь для прохождения по объектам Animal в коллекции можно использовать такой код:

foreach (Animal myAnimal in animalCollection) {

Console.WriteLine( New {0} object added to custom collection, +

Name = {1} , myAnimal.ToString (), myAnimal.Name);

Обратитесь к проекту DictionaryAnimals в загружаемом коде для данной главы.

Глубокое копирование

в главе 9 уже рассказывалось, как выполнять поверхностное копирование с помощью защищенного метода System. Object .MemberwiseClone (), реализуя метод, подобный GetCopy:

public class Cloner {

public int Val;

public Cloner(int newVal)

Val = newVal;

public object GetCopy0 {

return MemberwiseClone0;

Теперь давайте предположим, что имеющиеся поля представляют собой не типы-значения, а ссылочные типы (например, объекты):

public class Content {

public int Val;

public class Cloner {

public Content MyContent = new Content () ;

public Cloner(int newVal) {

MyContent.Val = newVal;

public object GetCopy0 {

return MemberwiseClone0;



В таком случае при поверхностном копировании методом GetCopyO появится поле, ссылающееся на тот же объект, что и исходный. Следующий код, в котором используется данный класс С lone г, иллюстрирует последствия поверхностного копирования ссылочных типов:

Cloner mySource = new Cloner (5) ;

Cloner myTarget = (Cloner)mySource.GetCopy();

Console.WriteLine( myTarget.MyContent.Val = {0} , myTarget.MyContent.Val); mySource.MyContent.Val = 2;

Console.WriteLine( myTarget.MyContent.Val = {0} , myTarget.MyContent.Val);

Здесь в четвертой строке, где присваивается значение полю mySource. MyContent. Val (т.е. общедоступному полю Val общедоступного поля MyContent исходного объекта), также изменяется и значение myTarget. MyContent. Val. Объясняется это тем, что mySource. MyContent ссылается на экземпляр того же самого объекта, что и myTarget .MyContent. Поэтому вывод показанного выше кода будет выглядеть следующим образом:

myTarget.MyContent.Val = 5 myTarget.MyContent.Val = 2

Обойти эту проблему можно, выполнив глубокое копирование. Конечно, для этого можно соответствующим образом изменить применявшийся ранее метод GetCopy (), но все-таки лучше использовать стандартный подход .NET Framework, т.е. реализовать интерфейс ICloneable, который имеет единственный метод Clone (). Этот метод не принимает параметров и возвращает результат типа object, что делает его сигнатуру идентичной сигнатуре применяемого ранее метода GetCopy ().

Чтобы изменить предыдущие классы, попробуйте воспользоваться следующим кодом глубокого копирования:

public class Content {

public int Val;

public class Cloner : ICloneable

public Content MyContent = new Content ();

public Cloner(int newVal)

MyContent.Val = newVal;

public object Clone 0 {

Cloner clonedCloner = new Cloner (MyContent.Val) ; return clonedCloner;

Здесь был создан новый объект Cloner с использованием поля Val объекта Content, содержавшегося в исходном объекте Cloner (MyContent). Данное поле представляет собой тип-значение, поэтому необходимости в глубоком копировании нет.

Использование кода, подобного только что показанному, для тестирования поверхностного копирования, но только с применением метода Clone () вместо GetCopy (), приведет к получению следующего результата:

myTarget.MyContent.Val = 5 myTarget.MyContent.Val = 5

Ha этот раз содержащиеся объекты являются независимыми. Обратите внимание на то, что иногда, в частности, в более сложных системах объектов, вызовы метода



Clone () могут осуществляться рекурсивно. Например, если бы поле MyContent класса Cloner тоже нуждалось в глубоком копировании, тогда могло бы потребоваться использовать следующий код:

public class Cloner : ICloneable {

public Content MyContent = new Content ();

public object Clone 0 {

Cloner clonedCloner = new Cloner () ; clonedCloner .MyContent = MyContent.Clone () ; return clonedCloner;

Здесь для упрощения синтаксиса создания нового объекта Cloner вызывается конструктор по умолчанию. Для функционирования этого кода еще потребовалось бы реализовать в классе Content интерфейс ICloneable.

Добавление возможности глубокого копирования в CardLib

Применить все это на практике можно, реализовав с использованием интерфейса ICloneable возможность для копирования объектов Card, Cards и Deck. Подобное может быть полезно в некоторых карточных играх, где не требуется, чтобы две колоды ссылались на один и тот же набор объектов Card, но, возможно, при этом нужно, чтобы порядок в одной колоде выглядел точно так же, как и в другой.

Реализация функции клонирования для класса Card в ChllCardLib выглядит просто, поскольку для него вполне достаточно и только возможности поверхностного копирования (ведь в нем содержатся только данные типа значений, в виде полей). Поэтому просто внесите в определение этого класса следующие изменения:

public class Card : ICloneable

public object Clone 0 {

return MemberwiseClone () ;

Обратите внимание, что данная реализация ICloneable подразумевает выполнение лишь поверхностного копирования. Никакого правила, которое бы определяло, что должно происходить в методе Clone (), нет, и для преследуемых здесь целей этого вполне достаточно.

Далее реализуйте интерфейс ICloneable для класса коллекции Cards. Это будет немного сложнее, поскольку клонироваться должен каждый объект Card в исходной коллекции, что требует глубокого копирования:

public class Cards : CollectionBase, ICloneable

public object Clone 0 {

Cards newCards = new Cards () ; foreach (Card sourceCard in List) {

newCards.Add(sourceCard.Clone() as Card);

return newCards;



1 ... 94 95 96 [ 97 ] 98 99 100 ... 396

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