7

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?

ruffin
  • 16,507
  • 9
  • 88
  • 138
Farah_online
  • 561
  • 1
  • 9
  • 20

4 Answers4

12

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();
Ani
  • 111,048
  • 26
  • 262
  • 307
  • 1
    But important to note in the general case that [implementing `ICloneable` doesn't guarantee clones will be deep copies](https://learn.microsoft.com/en-us/dotnet/api/system.icloneable?view=netcore-3.1#notes-to-implementers): "_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._" – ruffin Sep 08 '20 at 17:12
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());
Fr33dan
  • 4,227
  • 3
  • 35
  • 62
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.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
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)

Ilia G
  • 10,043
  • 2
  • 40
  • 59