System.Array.CopyTo() 和 System.Array.Clone() 之间的区别
Posted
技术标签:
【中文标题】System.Array.CopyTo() 和 System.Array.Clone() 之间的区别【英文标题】:Difference between the System.Array.CopyTo() and System.Array.Clone() 【发布时间】:2010-09-16 22:38:57 【问题描述】:System.Array.CopyTo()
和 System.Array.Clone()
有什么区别?
【问题讨论】:
有点愚蠢的面试问题。 “我不记得了,让我检查一下文档……” 【参考方案1】:Clone() 方法返回一个包含原始数组中所有元素的新数组(浅拷贝)对象。 CopyTo() 方法将元素复制到另一个现有数组中。两者都执行浅拷贝。浅拷贝意味着内容(每个数组元素)包含对与原始数组中的元素相同的对象的引用。深拷贝(这两种方法都不执行)会为每个元素的对象创建一个新实例,从而产生一个不同但相同的对象。
所以区别是:
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.
编辑:
删除错误的例子。
【讨论】:
你的例子是错误的。在第一个中,numbersCopy
只是对分配给numbers
的数组的另一个引用。这与使用CopyTo()
方法不相同。如果您使用CopyTo()
,您将获得与Clone()
示例中相同的结果。此外,这是 C# - System.out.println
应该是 Console.WriteLine
。
这个答案,正如其他人所说的,误导是从这里复制粘贴:geekswithblogs.net/dforhan/archive/2005/12/01/61852.aspx
根据GenZiy的例子,两者都是浅拷贝。 Array 的浅拷贝只复制 Array 的元素,无论它们是引用类型还是值类型,但它不会复制引用所引用的对象。新 Array 中的引用指向的对象与原始 Array 中的引用指向的对象相同。相反,Array 的深层副本复制元素以及元素直接或间接引用的所有内容。 msdn.microsoft.com/en-us/library/system.array.clone.aspx
@PatrickDesjardins 。这对我来说不是很清楚。如果两者都是浅拷贝那么什么是深拷贝。为什么 CopyTo() 是浅拷贝。
在 .Net 3.5 中,Linq 的 ToArray()
方法提供了一种更简单(并且类型化)的浅克隆数组的方法。由于 Array 是 IENumerable<T>
它可以使用它。【参考方案2】:
到目前为止没有提到的另一个区别是
Clone()
目标数组不需要存在,因为新数组是从头开始创建的。
对于CopyTo()
,不仅目标数组需要已经存在,它还需要足够大以容纳源数组中您指定为目标的索引中的所有元素。
【讨论】:
【参考方案3】:正如许多其他答案中所述,这两种方法都执行数组的shallow copies。但是,存在尚未解决的差异和建议,并在以下列表中突出显示。
System.Array.Clone
的特点:
CopyTo
慢可能是因为它使用了 Object.MemberwiseClone
;
需要将结果转换为适当的类型;
生成的数组与源数组的长度相同。
System.Array.CopyTo
的特点:
Clone
快;
它调用Array.Copy
继承的能力,是最有用的:
可以将值类型元素装箱成引用类型元素,例如将int[]
数组复制到object[]
中;
可以将引用类型元素拆箱成值类型元素,例如,将装箱int
的object[]
数组复制到int[]
中;
可以对值类型执行扩展转换,例如,将int[]
复制到long[]
。
可以向下转换元素,例如,将Stream[]
数组复制到MemoryStream[]
(如果源数组中的任何元素不能转换为MemoryStream
,则会引发异常)。
允许将源复制到长度大于源的目标数组。
另外请注意,这些方法可用于支持ICloneable
和ICollection
,因此如果您正在处理数组类型的变量,则不应使用Clone
或CopyTo
,而应使用Array.Copy
或@ 987654329@。受约束的复制确保如果复制操作无法成功完成,则目标阵列状态不会损坏。
【讨论】:
这是可靠的信息。那么我们为什么不写一个更快的通用版本的克隆呢?类似于: 例如:public static T[] ExtFastClone.ToArray()
方法。无论如何它都会创建一个副本,并且可以在任何IEnumerable<>
上执行,包括数组。与.Clone()
不同,它是类型化的,因此不需要强制转换。【参考方案4】:
正如@PatrickDesjardins 所说,两者都执行浅拷贝(尽管许多被误导的人认为CopyTo
做了深拷贝)。
但是,CopyTo
允许您将一个数组复制到目标数组中的指定索引,从而显着提高了灵活性。
【讨论】:
【参考方案5】: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
【讨论】:
我猜,浅拷贝意味着只复制引用,而不是值。因此,如果您将 myarray[0] 的值从“one”更改为 0,那么 myarray1[0] 和 myarray[1] 的值不应该也为 0。 抱歉,您的猜测是错误的。浅拷贝不是引用的拷贝:“MemberwiseClone 方法通过创建一个新对象,然后将当前对象的非静态字段复制到新对象中来创建一个浅拷贝。”见msdn.microsoft.com/en-us/library/… 浅拷贝或深拷贝如果您放入数组中的类型是原始/不可变的,则无关。字符串和整数总是在放入其他东西时会生成一个新副本。要测试深拷贝,请在其中一个点上放置一个复杂对象(如数组)。【参考方案6】:CopyTo() 和 Clone() 都进行浅拷贝。 Clone() 方法对原始数组进行克隆。它返回一个精确长度的数组。
另一方面,CopyTo() 将元素从原始数组复制到目标数组,从指定的目标数组索引开始。请注意,这会将元素添加到已经存在的数组中。
以下代码将与说 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);
让我解释一下。如果数组的元素是引用类型,则副本(对于 Clone() 和 CopyTo())将被制作到第一(顶层)级别。但是较低的级别不会被复制。如果我们还需要较低级别的副本,我们必须明确地这样做。这就是为什么在克隆或复制引用类型元素之后,克隆或复制数组中的每个元素都引用与原始数组中相应元素引用的相同内存位置。这清楚地表明没有为较低级别创建单独的实例。如果是这样,那么更改复制或克隆数组中任何元素的值都不会影响原始数组的相应元素。
我认为我的解释是详尽无遗的,但我没有其他方法可以使其易于理解。
【讨论】:
【参考方案7】:Array.Clone()
将在将int
的数组或字符串作为引用传递给方法时执行技术上的深度复制。
例如
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
即使方法对数字数组进行排序,但它不会影响传递给排序方法的实际引用。即数字数组将在第 1 行中采用相同的未排序初始格式。
注意:克隆应该在排序方法中完成。
【讨论】:
【参考方案8】:Clone()
方法不引用目标实例只是给你一个副本。
CopyTo()
方法将元素复制到现有实例中。
两者都没有给出目标实例的引用,正如许多成员所说,他们给出了没有引用的浅拷贝(幻觉拷贝),这是关键。
【讨论】:
【参考方案9】:两者都是浅拷贝。 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 */
【讨论】:
【参考方案10】:Array.Clone 在调用函数时不需要目标/目标数组可用,而 Array.CopyTo 需要目标数组和索引。
【讨论】:
【参考方案11】:Clone()
仅用于复制数据/数组的结构,它不复制实际数据。
CopyTo()
复制结构和实际数据。
【讨论】:
【参考方案12】:请注意:使用 String[] 和 StringBuilder[] 是有区别的。
在 String 中 - 如果您更改 String,我们复制(通过 CopyTo 或 Clone)指向相同字符串的其他数组不会改变,但是原始 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
【讨论】:
这与CopyTo
和Clone
无关。它只是引用语义与值语义。 int 是一种值类型,因此您每次都会获得一个新副本。 StringBuilder 具有引用语义,因此您正在对同一个副本进行操作。
@nawfal - 我知道,这就是我写“请注意”的原因...... String、StringBuilder 和 int 在 copyto 和 clone 中的行为有所不同,这可能会让您感到困惑不知道的人。以上是关于System.Array.CopyTo() 和 System.Array.Clone() 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章