克隆方法和直接将实例分配给另一个方法有什么区别

本文关键字:方法 另一个 什么 区别 分配 实例 | 更新日期: 2023-09-27 18:17:49

我想知道,如果我有一个名为 Test 的类,下面有什么区别

Test test = new Test();
Test newTest = test;
Test newTest2 = test.Clone();

newTest 和 newTest2 有什么区别?有人可以帮忙吗?提前感谢!

克隆方法和直接将实例分配给另一个方法有什么区别

分配实例时,如果Test是一个类,则实际上是在复制引用,但testnewTest都将指向内存中的同一实例。

这意味着两个变量都指向同一个对象:

Test test = new Test();
test.Foo = 24;
Test newTest = test;
newTest.Foo = 42;
Console.WriteLine(test.Foo); // Prints 42!

另一方面,Clone()通常用于指示对象本身的副本,这意味着testnewTest2将指向不同的对象,因此不会发生上述情况。

请注意,如果 test 是 struct(值类型(,则直接赋值实际上是对象的完整(浅表(副本(按值(。

要理解这种区别,必须首先了解对象引用是什么。 由于术语"引用"用于指代许多不同的概念,因此我喜欢术语"对象ID"。 使用汽车类比,对象 ID 是一张纸条,上面有汽车的 VIN。 如果你递给油漆店一张写有"VIN ZX357"的纸,并要求商店把它涂成蓝色,商店不会把纸条涂成蓝色,而是他们会找到带有该VIN号的汽车并将那辆车涂成蓝色。

如果一个人有一个类型为Car(引用类型(的变量Wuzzle恰好持有"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(,Fuzzle将持有新的VIN而不是3941QXY5(。 说Wuzzle.Color = Orange会把汽车3941QXY5涂成橙色,但不会影响汽车QL793。

接口类型的变量的处理方式与任何其他引用类型相同。 可以用IColorizable代替Car,行为将完全相同。

需要注意的是,ICloneable不是一个很好的接口;ICloneable<T>一个更好的接口返回一个类型为 T 的对象。 此接口有两个主要优点:

  1. 使用 ICloneable ,有必要将返回类型类型转换为所需的对象类型。 这有点丑。 ICloneable<T>消除了此要求。
  2. 对于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()返回一个新实例并执行深度复制(这实际上取决于您的实现(,newTest2指的是一个完全独立的对象,则test中的任何更改都不会影响它。

新测试实际上指向内存中与测试相同的对象,因此修改 newTest 会更改测试。 newTest2 实际上是测试的副本。