如何在没有正确引用的情况下克隆多维数组?

时间:2014-11-29 23:42:28

标签: c# arrays multidimensional-array clone deep-copy

我的程序中有三维数组。我想在其中调试值,并将此数组放入另一个数组中,我希望在其中找到差异。

我试过了:

Weights weights = new Weights(); // init inside
List<Weights> weightsDebug = new List<Weigts>();
weightsDebug.Add(weights); // I'd put first weigths into the list 
for(int i = 0; i < 100; i++) {
    // do some bad things with weights;
    weightsDebug.Add(weights);
}

之后,我在weigthsDebug的所有99个元素中的权重值都相同。我试图调试,我意识到,weigts数组正在改变。我知道问题在于引用(按链接复制,而不是按值复制) - 所有推送到weightsDebug数组元素都与主循环中的weights链接。

我搜索了一下,发现了一些如何复制1维数组的方法。我接下来尝试了:

我在我的Weights课程中添加了Clone方法:

double[][][] values;
public Weights Clone() {
    Weights clone = new Weights();
    clone.values = (double[][][]) this.values.Clone();
    return clone;
}

public Weights()
{
    Console.WriteLine("Constructor WITHOUT arguments fired");
}

现在我在复制权重时这样做:

Weights weights = new Weights(); // init inside
List<Weights> weightsDebug = new List<Weigts>();
weightsDebug.Add(weights); // I'd put first weigths into the list 
for(int i = 0; i < 100; i++) {
    // do some bad things with weights;
    Weights weightsClone = weights.Clone();
    weightsDebug.Add(weightsClone);
}

我仍然在整个调试阵列中获得最后更改的值。我怎么纠正它?

2 个答案:

答案 0 :(得分:2)

您真正在寻找的是深度克隆,而不是您正在实施的当前浅层克隆。

很久以前,我们意识到通过创建类Serializable,我们可以使用.Net serialization类来快速,轻松,正确地对任何对象进行深度克隆。

以下是我们用于此深度克隆的方法(还有一个使用DataContractSerializer的SilverLight变体):

    /// <summary>
    /// This method clones all of the items and serializable properties of the current collection by 
    /// serializing the current object to memory, then deserializing it as a new object. This will 
    /// ensure that all references are cleaned up.
    /// </summary>
    /// <returns></returns>
    /// <remarks></remarks>
    public T CreateSerializedCopy<T>(T oRecordToCopy)
    {
        // Exceptions are handled by the caller

        if (oRecordToCopy == null)
        {
            return default(T);
        }

        if (!oRecordToCopy.GetType().IsSerializable)
        {
            throw new ArgumentException(oRecordToCopy.GetType().ToString() + " is not serializable");
        }

        var oFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

        using (var oStream = new MemoryStream())
        {
            oFormatter.Serialize(oStream, oRecordToCopy);
            oStream.Position = 0;
            return (T)oFormatter.Deserialize(oStream);
        }
    }

要使用此功能,请首先确保使用Serializable属性标记Weights类:

[Serializable]
public class Weights

然后你可以根据需要克隆:

        var weights = new List<Weights>();
        weights.Add(new Weights());

        var debugWeights = CreateSerializedCopy<List<Weights>>(weights);

        if (debugWeights[0] == weights[0])
        {
            System.Diagnostics.Debug.WriteLine("Did not serialize correctly");
        }

答案 1 :(得分:1)

这里的问题是你没有一个真正的多维数组,只有一个对象。你有一个&#34;锯齿状的&#34;多维数组,其中对象实际上是数组数组的数组。这意味着要克隆对象,您需要做更多的工作:

clone.values = new double[values.Length][][];

for (int i = 0; i < values.Length; i++)
{
    clone.values[i] = new double[values[i].Length][];

    for (int j = 0; j < values[i].Length; j++)
    {
        clone.values[i][j] = (double[])values[i][j].Clone();
    }
}