tags:

views:

142

answers:

5

I pass a 2dimensional array as a property to my user control. There i store this values in another 2dimensional array:

int[,] originalValues = this.Metrics;

Later i change values in this.Metrics. But now if I retrieve values from originalValues, i get the changed values from this.Metrics. How do I make a deep copy and don't just copy the references in C#?

+5  A: 

You can clone an array, which makes a copy of it:

int[,] originalValues = (int[,])this.Metrics.Clone();
Pieter
Clone does not make a deep copy (except int he trivial cases of value type arrays).
John Nicholas
Little secret: the question is about an int array. Anything else than this would be quite overkill.
Pieter
lol, i was just answering the general question. Why ask for a deep copy of a value type?
John Nicholas
I think the OP thinks this is an array of arrays, not a multi dimensional array :).
Pieter
I dont know but in Java I always called this a 2dimensional array and nobody disagreed ;) Any yes, I need it only for ints.
Roflcoptr
In .NET, this is one data structure. The `Clone()` will be enough.
Pieter
Yes thanks. This works fine. I'll accept this answer. Although the other are also great, this is just the simples solution for my problem. Thanks to all!
Roflcoptr
You're welcome.
Pieter
A: 

you need to create a new array

you then need to manually copy the value of each element into the new array

What you are doing in the example given is create 2 array variables which both reference the same array.

the problem with the clone method is that it is a shallow copy.

In this isntance because you are using int it does not mater. Howver if you had an array of classes the definition of the ICLonable interface leaves it ambiguous as to how deep the clone will go.

Imagine if you had a class that has properties that are other classes which has properties that are other classes.

The clonable interface does not state whether it will also clone the sub members or not. Moreover many people have different views on what the expected behaviour is

hence why it is often recommended to define 2 interfaces ... IShallowCopy and IDeepCopy

John Nicholas
+1  A: 

If the object you are copying is an array then you can use:

Array.Copy(sourceArray, destinationArray, sourceArray.Count)

This will give you a seperate copy of the original array into your destination array.

Brian Scott
+4  A: 

I don't know where I got this from, but this works well for me.

public static class GenericCopier<T>    //deep copy a list
    {
        public static T DeepCopy(object objectToCopy)
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryFormatter.Serialize(memoryStream, objectToCopy);
                memoryStream.Seek(0, SeekOrigin.Begin);
                return (T)binaryFormatter.Deserialize(memoryStream);
            }
        }
    }
Mark W
+1  A: 

The crux of your problem is here:

There i store this values in another 2dimensional array

This is actually inaccurate. You are not creating a new array; you are setting your originalValues variable to the same array. For a more detailed explanation, see below.


The confusion expressed in the comments to Pieter's answer is due to some uncertainty surrounding the term "deep copy."

When it comes to copying objects, there's deep copying and shallow copying.

Deep copying involves making a copy of all the data belonging to an object, which means that if the object includes members which are themselves complex (e.g., instances of user-defined reference types), those objects must be deep-copied as well (along with all of their members, and so on).

Shallow copying involves simply copying all of the fields from one object to another, which means that if the object includes reference types, only the references need to be copied (and so the copied references will be pointing to the same objects).

In the case of the code you've posted:

int[,] originalValues = this.Metrics;

...there's actually no copying of any objects at all. All you've done is copied a single reference, assigning the value of this.Metrics (a reference) to the variable originalValues (also a reference, to the very same array). This is essentially the same as a simple value assignment, like this:

int x = y; // No objects being copied here.

Now, the Array.Clone method makes, in fact, a shallow copy. But as Pieter pointed out, there's really no difference between a "shallow" or "deep" copy of an array of integers, since integers are not complex objects.

If you had something like this:

StringBuilder[,] builders = GetStringBuilders();
StringBuilder[,] builderCopies = (StringBuilder[,])builders.Clone();

...what would happen is you'd end up with a whole new array (a copy, yes), but one containing all of the same StringBuilder objects (so a shallow copy). This is where deep versus shallow copying comes into play; if you wanted a a new array containing copies of all of the StringBuilder objects from builders, you'd need to make a deep copy.

Dan Tao