如何手动创建一个深拷贝

6

按照这个网站http://www.csharp411.com/c-object-clone-wars/的方法,我决定手动创建一个类的深度拷贝(遵循第一种方法:手动克隆)。我实现了克隆接口和必要的属性。我运行程序并检查我的克隆是否与原始实例相等。这是正确的。

然而,我的新实例仍然引用原始实例。所以在我的副本中进行的任何更改都会反映到原始实例中。

那么如果这不会创建深度拷贝,那么什么会呢?出了什么问题吗?

(我想手动制作深度拷贝以提高性能,所以我不想使用ObjectCopier类。(即使它工作得很好,但它占用了代码运行时间的90%))。

代码片段:

类实现:

public class SudokuAlgorithmNorvig: ICloneable
{

克隆方法:

    public object Clone()
    {
        SudokuAlgorithmNorvig sudokuClone = new SudokuAlgorithmNorvig(this.BlockRows, this.BlockColumns);

        sudokuClone.IsSucces = this.IsSucces;

        if (this.Grid != null) sudokuClone.Grid = (Field[,])this.Grid;
        if (this.Peers != null) sudokuClone.Peers = (Hashtable)this.Peers;
        if (this.Units != null) sudokuClone.Units = (Hashtable)this.Units;

        return sudokuClone;
    }

克隆方法调用:

SudokuAlgorithmNorvig sudokuCopy = (SudokuAlgorithmNorvig)sudoku.Clone()

我在所有其他类中也做了同样的事情(实现和设置克隆方法)。(Field + Coordinate)


2
我们需要看到你的代码才能确定问题出在哪里。提供能够展示问题的最短代码示例是最好的选择。 - Matthew Watson
1
是的,我已经意识到了 :) 现在开始实现,谢谢。 - dylanmensaert
1
好的,看起来你只是对对象进行了浅克隆。例如,sudokuClone.Grid = (Field[,])this.Grid并没有将sudokuClone.Grid指向一个新的副本! - Matthew Watson
我不确定它是否像C#,但如果它像Java一样,由于你将所有对象(字段、对等体、单元)分配给克隆体,它们是通过引用传递的。你需要使用new运算符为每个对象创建深拷贝,这就是为什么大多数对象都有一个以自身类型为参数的构造函数的原因。 - SGM1
@SGM “这就是为什么大多数对象必须具有以自身类型作为参数的构造函数”的含义在C#中不适用。 - I4V
1个回答

3

看起来你在许多地方创建了对现有对象的引用,而不是创建副本。

BlockRowsBlockColumns是你传递给新对象的自定义对象吗?那些只会是现有对象中BlockRowsBlockColumns的引用,所以在第一个对象中更改其中一个实例将反映在第二个对象中。

我不知道GridPeersUnits代表什么,但那些很可能也是引用。你需要使所有这些类也可克隆。否则,在SudokuAlgorithmNorvig类的第一个实例中更改Grid将更改第二个实例中相应的Grid


好的,blockrows和blockcolumns是在SudokuAlgorithmNorvig的构造函数中设置的。所以我不知道如何克隆它。 - dylanmensaert
网格是一个类型为Field的二维数组(自定义类,在其中以相同方式实现了克隆)。对等方和单元是哈希映射,也包含Field。那么我是否需要对哈希映射和数组进行特殊处理才能进行克隆? - dylanmensaert
如果像Java一样,我相信所有的原始类型,如int、double、char等都是按值传递的。 - SGM1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接