System.Array.CopyTo()和System.Array.Clone()之间的区别
System.Array.CopyTo()
和System.Array.Clone()
之间有什么区别?
Clone()方法返回包含原始数组中所有元素的新数组(浅拷贝)对象。 CopyTo()方法将元素复制到另一个现有的数组中。 两者都执行浅拷贝。 浅拷贝意味着内容(每个数组元素)包含与原始数组中元素相同的对象的引用。 深层副本(这些方法都不会执行)将创build每个元素对象的新实例,从而生成一个不同但同一个对象。
所以区别是:
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.
编辑:
删除错误的例子。
@PatrickDesjardins表示,尽pipe许多人误以为CopyTo
做了深层次的拷贝,但他们都performance得很浅。
但是, CopyTo
允许您将一个数组复制到目标数组中的指定索引,使其具有更大的灵活性。
目前还没有提到的另外一个区别是:
- 与
Clone()
目标数组需要不存在,因为从头开始创build一个新的。 - 与
CopyTo()
不仅目标数组需要已经存在,它需要足够大,以保持源数组中的所有元素从您指定的目标索引。
正如许多其他答案所述,这两种方法都可以执行数组的浅层副本 。 不过,还有一些尚未解决的差异和build议,并在以下列表中予以强调。
System.Array.Clone
特征:
- 使用.NET 4.0的testing显示它比
CopyTo
慢,可能是因为它使用了Object.MemberwiseClone
; - 需要将结果转换为适当的types;
- 结果数组的长度与源相同。
System.Array.CopyTo
特征:
- 复制到相同types的数组时, 速度
Clone
快 ; - 它调用
Array.Copy
inheritance是能力 ,是最有用的:- 可以将值types元素包装到引用types元素中,例如,将
int[]
数组复制到object[]
; - 可以将引用types元素转换为值types元素,例如,将boxed
int
的object[]
数组复制到int[]
; - 可以在值types上执行扩展转换,例如,将
int[]
复制到long[]
。 - 可以向下转换元素,例如,将
Stream[]
数组复制到MemoryStream[]
(如果源数组中的任何元素不能转换为MemoryStream
,则抛出exception)。
- 可以将值types元素包装到引用types元素中,例如,将
- 允许将源复制到长度大于源的目标数组。
还要注意,这些方法可用于支持ICloneable
和ICollection
,所以如果处理数组types的variables,则不应使用Clone
或CopyTo
,而应使用Array.Copy
或Array.ConstrainedCopy
。 受限制的副本确保如果复制操作无法完成成功,则目标arrays状态不会损坏。
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"
来源
CopyTo()和Clone()都是浅拷贝。 Clone()方法会对原始数组进行克隆。 它返回一个精确的长度数组。
另一方面,CopyTo()将元素从原始数组复制到指定的目标数组索引处的目标数组。 请注意,这会将元素添加到已经存在的数组中。
下面的代码将会与这个post相矛盾:CopyTo()生成一个深层副本:
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); }
让我稍微解释一下。 如果数组的元素是引用types,那么复制(Clone()和CopyTo())将被制作为第一个(顶部)级别。 但是较低的级别不会被复制。 如果我们还需要更低层次的副本,我们必须明确地做到这一点。 这就是为什么克隆或复制引用types元素之后,克隆或复制数组中的每个元素引用与原始数组中相应元素引用的内存位置相同的内存位置。 这清楚地表明没有单独的实例被创build为较低级别。 如果是这样,那么更改“复制”或“克隆”数组中任何元素的值都不会影响原始数组的相应元素。
我认为我的解释是详尽的,但我没有find其他可以理解的方式。
Clone()
用于复制只有数据/数组的结构,它不复制实际的数据。
CopyTo()
复制结构以及实际数据。
Clone()
方法不给参考目标实例只是给你一个副本。 CopyTo()
方法将元素复制到现有的实例中。
两者都没有提供目标实例的参考,许多成员说,他们给浅拷贝(幻想副本),而没有参考这是关键。
答案让我感到困惑。 当你说浅拷贝,这意味着他们仍然指向相同的地址。 这意味着,改变任何一个也会改变另一个。
所以如果我有A = [1,2,3,4],我克隆它,得到B = [1,2,3,4]。 现在,如果我改变B [0] = 9,这意味着A现在是A = [9,2,3,4]。 那是对的吗?
两者都是浅的副本。 CopyTo方法不是深度复制。 检查以下代码:
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 */
请注意:使用String []到StringBuilder []是有区别的。
在string中 – 如果你改变string,我们已经复制的其他数组(指向CopyTo或Clone)指向同一个string将不会改变,但原始的String数组将指向一个新的String,但是,如果我们使用一个StringBuilder在一个数组中,String指针不会改变,因此它会影响我们为这个数组所做的所有拷贝。 例如:
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 }