Deep Copy with Array
Asked Answered
E

5

8

Why doesn't ICloneable's Clone method return a deep copy?

Here is some sample code:

class A : ICloneable 
{
    public int x = 2;
    public A(int x)
    {
       this.x = x; 
    }
       
    public A copy()
    {
        A a = new A(this.x);
        return a; 
    }

     public object Clone()
     {
         A a = new A(this.x);
         return a;
     }
}

In the Main method :

A[] Array1 = new A[4] ;
Array1[0] = new A(0);
Array1[1] = new A(1);
Array1[2] = new A(2);
Array1[3] = new A(3);
A[] Array2 = new A[10];
Array. Copy(Array1, Array2, 4); 

Array2[2].x = 11; 
for (int i = 0; i < 4; i++)
    Console.WriteLine($"Index {i} value: {Array1[i].x}");

Remembering that I've only changed element index 2 in Array2, here is the output from the code above, listing the values in Array1:

Index 0 value: 0
Index 1 value: 1
Index 2 value: 11
Index 3 value: 3

Index 2 in Array1 has 11 even though I changed it in Array2 and class A implements ICloneable!

What then is the benefit of Array implementing ICloneable?

Elveraelves answered 12/8, 2010 at 3:52 Comment(0)
S
14

From http://msdn.microsoft.com/en-us/library/k4yx47a1.aspx:

"If sourceArray and destinationArray are both reference-type arrays or are both arrays of type Object, a shallow copy is performed. A shallow copy of an Array is a new Array containing references to the same elements as the original Array. The elements themselves or anything referenced by the elements are not copied"

There may be a better method than this, but one technique you could use is:

  A[] array2 = array1.Select (a =>(A)a.Clone()).ToArray();
Strander answered 12/8, 2010 at 4:0 Comment(1)
But important to note in the general case that implementing ICloneable doesn't guarantee clones will be deep copies: "The ICloneable interface simply requires that your implementation of the Clone() method return a copy of the current object instance. It does not specify whether the cloning operation performs a deep copy, a shallow copy, or something in between."Bydgoszcz
U
2

Array.Copy copies the values of the array, in this case, references. There is nothing in the documentation of Array.Copy() that indicates a check for classes that implement IClonable and call Clone() instead. You will need to loop through the array and call Clone() yourself.

BTW, yes, IClonable kind of sucks.

Unexceptional answered 12/8, 2010 at 4:0 Comment(0)
E
2

Array.Copy() does not use ICloneable. It simply copies values stored in each cell (which in this case are references to your A objects)

Elinoreeliot answered 12/8, 2010 at 4:0 Comment(0)
S
2

Ani's answer uses LINQ thus does not work for C# 2.0, however a same method can be done using the Array class's ConvertAll method:

A[] Array2 = Array.ConvertAll(Array1,a => (A)a.Clone());
Salinometer answered 30/4, 2014 at 18:20 Comment(0)
J
-1

This is an example of a deep copy using generic System.Array (and copying it to a new array that is twice as large):

    public Array ResizeArray( Array array1) {
        var size = array1.Length;
        var newSize = size * 2;
        var type = array1.GetValue(0)?.GetType();
        var array2 = Array.CreateInstance(type, newSize);

        for (int i = 0; i < size; i++) {
            array2.SetValue(array1.GetValue(i), i);
        }
        
        return array2;
    }
Joannejoannes answered 13/9, 2024 at 1:49 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.