System.Array. CopyTo()和 System.Array. Clone()之间的区别

System.Array.CopyTo()System.Array.Clone()有什么区别?

123218 次浏览

The Clone() method returns a new array (a shallow copy) object containing all the elements in the original array. The CopyTo() method copies the elements into another existing array. Both perform a shallow copy. A shallow copy means the contents (each array element) contains references to the same object as the elements in the original array. A deep copy (which neither of these methods performs) would create a new instance of each element's object, resulting in a different, yet identical object.

So the difference are :

1- CopyTo require to have a destination array when Clone return a new array.
2- CopyTo let you specify an index (if required) to the destination array.
Edit:

Remove the wrong example.

Both perform shallow copies as @PatrickDesjardins said (despite the many misled souls who think that CopyTo does a deep copy).

However, CopyTo allows you to copy one array to a specified index in the destination array, giving it significantly more flexibility.

One other difference not mentioned so far is that

  • with Clone() the destination array need not exist yet since a new one is created from scratch.
  • with CopyTo() not only does the destination array need to already exist, it needs to be large enough to hold all the elements in the source array from the index you specify as the destination.
object[] myarray = new object[] { "one", 2, "three", 4, "really big number", 2324573984927361 };


//create shallow copy by CopyTo
//You have to instantiate your new array first
object[] myarray2 = new object[myarray.Length];
//but then you can specify how many members of original array you would like to copy
myarray.CopyTo(myarray2, 0);


//create shallow copy by Clone
object[] myarray1;
//here you don't need to instantiate array,
//but all elements of the original array will be copied
myarray1 = myarray.Clone() as object[];


//if not sure that we create a shalow copy lets test it
myarray[0] = 0;
Console.WriteLine(myarray[0]);// print 0
Console.WriteLine(myarray1[0]);//print "one"
Console.WriteLine(myarray2[0]);//print "one"

the source

Clone() is used to copy only structure of data/array it doesn't copy the actual data.

CopyTo() copies the structure as well as actual data.

Both CopyTo() and Clone() make shallow copy. Clone() method makes a clone of the original array. It returns an exact length array.

On the other hand, CopyTo() copies the elements from the original array to the destination array starting at the specified destination array index. Note that, this adds elements to an already existing array.

The following code will contradict the postings saying that CopyTo() makes a deep copy:

public class Test
{
public string s;
}


// Write Main() method and within it call test()


private void test()
{
Test[] array = new Test[1];
array[0] = new Test();
array[0].s = "ORIGINAL";


Test[] copy = new Test[1];
array.CopyTo(copy, 0);


// Next line displays "ORIGINAL"
MessageBox.Show("array[0].s = " + array[0].s);
copy[0].s = "CHANGED";


// Next line displays "CHANGED", showing that
// changing the copy also changes the original.
MessageBox.Show("array[0].s = " + array[0].s);
}

Let me explain it a bit. If the elements of the array are of reference types, then the copy (both for Clone() and CopyTo()) will be made upto the first(top) level. But the lower level doesn't get copied. If we need copy of lower level also, we have to do it explicitly. That's why after Cloning or Copying of reference type elements, each element in the Cloned or Copied array refers to the same memory location as referred by the corresponding element in the original array. This clearly indicates that no separate instance is created for lower level. And if it were so then changing the value of any element in the Copied or Cloned array would not have effect in the corresponding element of the original array.

I think that my explanation is exhaustive but I found no other way to make it understandable.

The Clone() method don't give reference to the target instance just give you a copy. the CopyTo() method copies the elements into an existing instance.

Both don't give the reference of the target instance and as many members says they give shallow copy (illusion copy) without reference this is the key.

As stated in many other answers both methods perform shallow copies of the array. However there are differences and recommendations that have not been addressed yet and that are highlighted in the following lists.

Characteristics of System.Array.Clone:

  • Tests, using .NET 4.0, show that it is slower than CopyTo probably because it uses Object.MemberwiseClone;
  • Requires casting the result to the appropriate type;
  • The resulting array has the same length as the source.

Characteristics of System.Array.CopyTo:

  • Is faster than Clone when copying to array of same type;
  • It calls into Array.Copy inheriting is capabilities, being the most useful ones:
    • Can box value type elements into reference type elements, for example, copying an int[] array into an object[];
    • Can unbox reference type elements into value type elements, for example, copying a object[] array of boxed int into an int[];
    • Can perform widening conversions on value types, for example, copying a int[] into a long[].
    • Can downcast elements, for example, copying a Stream[] array into a MemoryStream[] (if any element in source array is not convertible to MemoryStream an exception is thrown).
  • Allows to copy the source to a target array that has a length greater than the source.

Also note, these methods are made available to support ICloneable and ICollection, so if you are dealing with variables of array types you should not use Clone or CopyTo and instead use Array.Copy or Array.ConstrainedCopy. The constrained copy assures that if the copy operation cannot complete successful then the target array state is not corrupted.

Please note: There is a difference between using String[] to StringBuilder[].

In String - if you change the String, the other arrays we have copied (by CopyTo or Clone) that points to the same string will not change, but the original String array will point to a new String, however, if we use a StringBuilder in an array, the String pointer will not change, therefore, it will affect all the copies we have made for this array. For instance:

public void test()
{
StringBuilder[] sArrOr = new StringBuilder[1];
sArrOr[0] = new StringBuilder();
sArrOr[0].Append("hello");
StringBuilder[] sArrClone = (StringBuilder[])sArrOr.Clone();
StringBuilder[] sArrCopyTo = new StringBuilder[1];
sArrOr.CopyTo(sArrCopyTo,0);
sArrOr[0].Append(" world");


Console.WriteLine(sArrOr[0] + " " + sArrClone[0] + " " + sArrCopyTo[0]);
//Outputs: hello world hello world hello world


//Same result in int[] as using String[]
int[] iArrOr = new int[2];
iArrOr[0] = 0;
iArrOr[1] = 1;
int[] iArrCopyTo = new int[2];
iArrOr.CopyTo(iArrCopyTo,0);
int[] iArrClone = (int[])iArrOr.Clone();
iArrOr[0]++;
Console.WriteLine(iArrOr[0] + " " + iArrClone[0] + " " + iArrCopyTo[0]);
// Output: 1 0 0
}

Both are shallow copies. CopyTo method is not a deep copy. Check the following code :

public class TestClass1
{
public string a = "test1";
}


public static void ArrayCopyClone()
{
TestClass1 tc1 = new TestClass1();
TestClass1 tc2 = new TestClass1();


TestClass1[] arrtest1 = { tc1, tc2 };
TestClass1[] arrtest2 = new TestClass1[arrtest1.Length];
TestClass1[] arrtest3 = new TestClass1[arrtest1.Length];


arrtest1.CopyTo(arrtest2, 0);
arrtest3 = arrtest1.Clone() as TestClass1[];


Console.WriteLine(arrtest1[0].a);
Console.WriteLine(arrtest2[0].a);
Console.WriteLine(arrtest3[0].a);


arrtest1[0].a = "new";


Console.WriteLine(arrtest1[0].a);
Console.WriteLine(arrtest2[0].a);
Console.WriteLine(arrtest3[0].a);
}


/* Output is
test1
test1
test1
new
new
new */

Array.Clone doesn't require a target/destination array to be available when calling the function, whereas Array.CopyTo requires a destination array and an index.

Array.Clone() would perform technically deep copy, when pass the array of int or string to a method as a reference.

For example

int[] numbers = new int[] { -11, 12, -42, 0, 1, 90, 68, 6, -9 };


SortByAscending(numbers); // Sort the array in ascending order by clone the numbers array to local new array.
SortByDescending(numbers); // Same as Ascending order Clone

Even if the methods sort the array of numbers but it wont affect the actual reference passed to the sorting methods.i.e the number array will be in same unsorted initial format in line no 1.

Note: The Clone should be done in the sorting methods.