1

I have 3-dimensional array in my programm. I want to debug values in it and I put this array into another array, in which I want to find difference.

I tried this:

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);
}

After that, I'd got same values in weights in all 99 elements of weigthsDebug. I'd tried to debug and I'd realised, that weigts array is being changed. I understood that problem is in the reference (copy by link, not by value) – all pushed to weightsDebug array elements are linked with weights in main loop.

I'd googled a bit and found some ways how to copy 1-dimensional array. I'tried next:

I added Clone method to my Weights class:

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");
}

Now I am doing so when copy weights:

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);
}

And I am still getting last changed value in whole debug array. How I can correct it?

2 Answers 2

2

What you really are looking for here is deep cloning rather than the current shallow cloning that you are implementing.

A long time ago, we realized that by making the classes Serializable, we could use the .Net serialization classes to quickly, easily, and correctly make deep clones of any object.

Here is a method that we use for this deep cloning (there is also a SilverLight variation that uses DataContractSerializer):

    /// <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);
        }
    }

To use this, first ensure the Weights class is tagged with the Serializable attribute:

[Serializable]
public class Weights

Then you can clone as needed:

        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");
        }
Sign up to request clarification or add additional context in comments.

2 Comments

Frankly, using a heavy-weight feature like serialization to address a light-weight need like simply copying some arrays is complete overkill. It's a fine general-purpose solution for other scenarios, but here it's just a waste of CPU and memory resources.
@PeterDuniho: the problem is that thinking like this often boxes developers into corners and produces serious implementations issues down the road. For example, what happens when another developer adds another property to the class down the road, but doesn't realize it isn't cloned? I have seen this happen so many times and cause actual production issues for customers that any additional CPU that is used is more than worth the stability that the solution provides. If CPU usage is really that much of a concern, then cloning probably shouldn't be used in the first place.
1

The problem here is that you don't have a true multi-dimensional array, where there's just a single object. You have a "jagged" multi-dimensional array, where the object is actually an array of arrays of arrays. This means that to clone the object, you need to do more work:

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();
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.