这与"Watson et al: Beginning Visual C# Chapter 10: 练习 4"有关:在 People 类上实现 ICloneable 接口以提供深度复制功能
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;
}
在 Person 类中,我们有:
public object Clone()
{
Person newPerson = new Person();
newPerson = (Person)newPerson.MemberwiseClone();
newPerson.Age = age;
newPerson.Name = name;
return newPerson;
}
要在程序.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);
}
这有效,并保留了"米克"的原始值。但问题是首先在人和人类上实现":ICloneable"。无论有没有它,代码的工作方式都是一样的。
一个相关的问题是他们所谓的运行ICloneable的"递归"实现的有效性。
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;
}
}
我悲惨地试图让这个递归工作,但我们最终得到的只是一个 StackOverflow。除了使用全局/静态变量退出循环之外,是否存在一种优雅的方法来"递归"地实现这种方式?
clonedCloner.MyContent = MyContent.Clone();
内容类不实现 ICloneable,因此此语句无法编译。 你有点迷茫,我看不出你实际使用了哪个克隆实现,以及这个类与 Person 有什么关系。
请注意,您实际上并没有测试您是否获得了深度克隆。 您仅通过检查集合是否未被修改来测试浅层克隆案例。 例如,深度克隆测试会改变 Mick 的属性,并检查原始集合是否仍然具有未修改的 Mick。 这才是"深"的真正含义。 这在您的代码中是可以的,但是您使用 MemberwiseClone() 会失去优雅点,它不会做任何有用的事情,并且与深度克隆相反。
坦率地说,这本书并没有教你很好的实践。 ICloneable 接口勉强逃脱了弃用,应避免使用。 这是一个损坏的接口,它不允许调用方指定是否需要深层副本或浅副本。 很多时候,它被实现为一个浅拷贝,因为它既便宜又容易,而调用者真的想要一个深拷贝。 产生一个很难诊断的讨厌的错误。
如果要支持深度克隆,只需向类中添加一个Person DeepClone()
方法即可。 现在它是显式和类型安全的。
不要纠缠于此,继续阅读本书。 一定要考虑找一个更好的。
/* 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
*/
/* 注意输出,当一个对象的值被更改时,它不会影响别人。因此,当一个对象被克隆时,它的行为就像一个单独的对象 */