1

This relates to the "Watson et al: Beginning Visual C# Chapter 10: exercise 4": Implement the ICloneable interface on the People class to provide deep copying capability

class People : DictionaryBase: ICloneable

    public void DictAdd(Person newPerson)
    {
        Dictionary.Add(newPerson.Name, newPerson);

    public object Clone()
    {

        People newPeople = new People();


        foreach (Person myPerson in Dictionary.Values)
        {
            Person ClonePerson = (Person)myPerson.Clone();
            newPeople.DictAdd(ClonePerson);
        }

        return newPeople;
    }

In the Person class we have:

        public object Clone()
    {
        Person newPerson = new Person();
        newPerson = (Person)newPerson.MemberwiseClone();
        newPerson.Age = age;
        newPerson.Name = name;
        return newPerson;

    }

To test it in Program.cs:

People clonedPeople = (People)PeopleCollection.Clone();

        PeopleCollection.Remove("Mick");
        myPerson1.Name = "Jock";
        myPerson1.Age = 13;
        PeopleCollection.DictAdd(myPerson1);


        Console.WriteLine("In the current collection \"Mick\" is now: \"{0}\" and his age is: {1}", myPerson1.Name, myPerson1.Age);
        Console.WriteLine("But \"Mick\" should remain in the original collection, now cloned.");
        foreach (DictionaryEntry p in clonedPeople)
        {
            Console.WriteLine();
            Console.WriteLine("myPerson Name: {0} myPerson.Age: {1}", ((Person)p.Value).Name, ((Person)p.Value).Age);
        }

This works, and the original values of "Mick" are preserved. But the question is to the point of implementing ": ICloneable" on the Person and People class in the first place. The code works the same with or without it.

A related question is to the efficacy of what they call running a "recursive" implementation of ICloneable in their example

 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()
     {
     Cloner clonedCloner = new Cloner(MyContent.Val);
     return clonedCloner;
     }
 }           

Have attempted miserably to get this recursion to work, but all we end up with is a StackOverflow. Short of using a global/static variable to quit the loop, does there exist an elegant way to implement this "recursively?"

4

2 回答 2

4
  clonedCloner.MyContent = MyContent.Clone();

Content 类未实现 ICloneable,因此该语句无法编译。你有点迷失了,我看不出你实际使用了哪个克隆器实现,以及这个类与 Person有什么关系。

请注意,您实际上并没有测试您是否获得了深度克隆。您仅通过检查集合是否被修改来测试浅克隆情况。例如,深度克隆测试会改变 Mick 的属性并检查原始集合是否仍有未修改的 Mick。这就是“深”的真正含义。这在你的代码中是可以的,但是你失去了使用 MemberwiseClone() 的优雅点,它没有做任何有用的事情并且与深度克隆相反。

坦率地说,这本书并没有教你很好的做法。ICloneable 接口险些被弃用,应该避免使用。这是一个损坏的接口,它不允许调用者指定是需要深拷贝还是浅拷贝。很多时候,它被实现为浅拷贝,因为它既便宜又容易,而调用者真的想要一个深拷贝。产生一个很难诊断的讨厌的错误。

如果你想支持深度克隆,那么只需Person DeepClone()在你的类中添加一个方法。现在它是显式类型安全的。

不要纠结于此,继续看书。考虑找一个更好的。

于 2014-04-06T07:17:19.217 回答
1
/* Here is a simple program of Deep copy. This will help you to fully understand ICloneable Interface.

using System;

namespace ICloneableDemo
{

    class Program
    {
        class Demo : ICloneable
        {

            public int a, b;
            public Demo(int x, int y)
            {
                a = x;
                b = y;
            }

            public override string ToString()
            {
                return string.Format(" a : " + a + "  b: " + b);
            }


            public object Clone()
            {
                Demo d = new Demo(a, b);
                return d;
            }
        }


        static void Main(string[] args)
        {

            Demo d1 = new Demo(10, 20);
            Console.WriteLine(" d1 : "+d1);

            Demo d2 = (Demo)d1.Clone();
            Console.WriteLine(" d2 : " + d2);

            Demo d3 = (Demo)d2.Clone();
            Console.WriteLine(" d3 : " + d3);

            Console.WriteLine("Changing the value of d1");

            d1.a = 44; 
            d1.b = 33;


            Console.WriteLine(" d1 : " + d1);

            Console.WriteLine(" d2 : " + d2);

            Console.WriteLine(" d3 : " + d3);


            Console.WriteLine("Changing the value of d3");

            d3.a = 50;
            d3.b = 60;

            Console.WriteLine(" d1 : " + d1);

            Console.WriteLine(" d2 : " + d2);

            Console.WriteLine(" d3 : " + d3);


            Console.ReadKey();
        }
    }
}

/*Output:
 d1 :  a : 10  b: 20
 d2 :  a : 10  b: 20
 d3 :  a : 10  b: 20
Changing the value of d1
 d1 :  a : 44  b: 33
 d2 :  a : 10  b: 20
 d3 :  a : 10  b: 20
Changing the value of d3
 d1 :  a : 44  b: 33
 d2 :  a : 10  b: 20
 d3 :  a : 50  b: 60
*/

/* 注意输出,当一个对象的值改变时,它不会影响其他对象。因此,当一个对象被克隆时,它的行为就像一个单独的对象 */

于 2017-11-11T20:28:56.650 回答