|
Программирование >> Программирование с использованием ajax
Для получения желаемого поведения в этот код можно добавить следующий простой итератор: 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;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |