【发布时间】:2011-12-15 03:10:14
【问题描述】:
我想知道,如果我有一个名为Test的类,下面有什么区别
Test test = new Test();
Test newTest = test;
Test newTest2 = test.Clone();
newTest 和 newTest2 有什么不同? 任何人都可以帮忙吗? 提前致谢!
【问题讨论】:
我想知道,如果我有一个名为Test的类,下面有什么区别
Test test = new Test();
Test newTest = test;
Test newTest2 = test.Clone();
newTest 和 newTest2 有什么不同? 任何人都可以帮忙吗? 提前致谢!
【问题讨论】:
当您分配实例时,如果Test 是一个类,您实际上是在复制引用,但test 和newTest 都将指向内存中的同一个实例。
这意味着两个变量都指向同一个对象:
Test test = new Test();
test.Foo = 24;
Test newTest = test;
newTest.Foo = 42;
Console.WriteLine(test.Foo); // Prints 42!
另一方面,Clone() 通常用于表示对象本身的副本,这意味着test 和newTest2 将指向不同的对象,因此不会发生上述情况。
请注意,如果 test 是 struct(值类型),则直接赋值实际上是对象的完整(浅)副本,按值。
【讨论】:
要了解区别,首先必须了解对象引用是什么。由于术语“引用”用于指代许多不同的概念,因此我喜欢术语“对象 ID”。使用汽车类比,对象 ID 是一张纸条,上面有汽车的 VIN。如果你把一张写有“VIN ZX357”的纸递给油漆店,让店家把它涂成蓝色,店家不会把纸条涂成蓝色,而是他们会找到那个VIN号的车把那辆车漆成蓝色。
如果有一个变量Wuzzle 的类型为Car(它是引用类型),恰好包含“VIN ZX357”,另一个变量Fuzzle,一个说Fuzzle = Wuzzle,那么Fuzzle 将——比如Wuzzle 持有“VIN ZX357”。仍然会有一辆车。一个人只有两张纸条,两张纸条都持有相同的 VIN,因此指的是同一辆车。像Wuzzle.Color=Purple 这样的语句会导致 VIN 为 ZX357 的汽车被涂成紫色。检查Fuzzle.Color 的请求将查看汽车 ZX357 并报告它是紫色的。
如果不是说Fuzzle = Wuzzle,而是说Fuzzle = (Car)(Wuzzle.Clone()),效果将是创建一辆与VIN ZX357类似的新车,只是它的VIN编号(例如QL793)和@987654331不同@ 将保留新的 VIN,而不是 3941QXY5)。说Wuzzle.Color = Orange 会将汽车 3941QXY5 涂成橙色,但不会影响汽车 QL793。
接口类型的变量被视为与任何其他引用类型一样。可以将IColorizable 替换为Car,行为将完全相同。
需要注意的是ICloneable 不是一个很好的界面;更好的接口是ICloneable<T>,它返回T 类型的对象。这个界面有两大优势:
ICloneable,有必要将返回类型转换为想要的对象类型。这有点难看。 ICloneable<T> 消除了这个要求。ICloneable,对象中的哪些对象引用应该按原样复制到克隆,以及哪些对象引用本身应该被克隆可能存在一些歧义。歧义并不像某些人所说的那么糟糕,但是通用的ICloneable<T> 可以使它更清晰一些。例如,如果有一个对象CloneableSortedList<T>,那么在该列表上调用ICloneable<CloneableSortedList<T>.Clone() 应该会返回一个新的CloneableSortedList,其中包含与原始类型T 相同的引用。相比之下,如果有一个CloneableSortedUserList,调用ICloneable<CloneableSortedUserList> 应该返回一个新的CloneableSortedUserList,它将用户的属性而不是用户对象引用视为值(因此如果它们是可变的则复制它们)。
【讨论】:
赋值只复制引用,而不是对象本身。
如果你的类实现了IClonable.Clone,可以写成执行深拷贝操作,即返回一个新分配的相同类型的对象,其字段是原本的。这是一个有趣的问题,当字段是引用类型时该怎么办:复制引用,还是深复制引用的对象?例如,Object.MemberwiseClone 仅复制引用(这称为浅复制),但如果您选择实现IClonable.Clone,则可以自行决定。
【讨论】:
Test newTest = test;
由于 Test 是一个引用类型(类),newTest 现在引用与 test 相同的对象。如果您更改对象 test 的引用,这将反映在 newTest 中,因为它们都引用了同一个对象。
Test newTest2 = test.Clone();
假设 Clone() 正在返回一个 new 实例并进行深层复制(这确实取决于您的实现),newTest2 指的是一个完全独立的对象,test 中的任何更改不会影响的。
【讨论】:
new test 实际上和 test 指向内存中的同一个对象,所以修改 newTest 会改变 test。 newTest2 实际上是 test 的一个副本。
【讨论】: