有很多初学者会对CopyTo()和Clone()的区别弄不清楚.在网上搜索一下,大多数解说的程序员都把问题引到浅拷贝和深拷贝的区别上去了,关于浅拷贝和深拷贝确实解释的很清楚,可是这并没有让初学者减轻疑惑.所以特此写点东西,解释下这两个方法的共同点和区别,同时解释下浅拷贝和深拷贝.
相信大多数C#程序员都有查阅MSDN的好习惯,但是MSDN中提到这两个方法最大的区别就是:一个方法创建了一个新Array对象,一个方法只是复制了Array引用.这句话本身没有错误,而且也正是他们的区别所在.只是这样会让人感到很迷惑.到底是什么区别呢?这里还是先说说他们的共同点:CopyTo()和Clone()都属于浅拷贝,这一点是毋庸置疑的.对于浅拷贝:如果数组中的成员为值类型(如:int,float,double,byte等),则完全复制数值到目标数组中,如果是引用类型(如用户自定义类型:class Student,class People,或者是类库中的类类型:ArrayList等),则指复制引用给目标数组.文字有时候不如代码来得容易理解.但是这里也许用图更容易理解,看下图:
假定创建一个学生类数组Student[],然后浅拷贝到另一个学生类数组Student1[]中.
从图中很容易看出所谓的浅拷贝对于引用类型,仅仅只是复制引用.通过一个数组修改内存中的值会影响另一个数组对内存对象的引用.
那么CopyTo()和Clone()方法的区别是什么呢?其实他们的区别,也就是MSDN上说的最大的区别就是用法上的区别.我们可以在VS弹出智能提示的时候看看他们的返回值,CopyTo()的返回值是void,使用方法如下Array1.CopyTo(Array2,0);其中Array2必须是一个已经实例化的数组.而Clone()的返回值是object.使用方法如下Array2 = Array1.Clone();其中Array2不必实例化.这样,我相信理解这两个方法的区别就很容易了.本质上并没有什么区别.都属于浅拷贝.如果拷贝所有的数组,就是用Clone().但是如果只是拷贝一部分,就可以选择CopyTo()了,CopyTo()的参数提示是这样的CopyTo(Array array,int Index).第二个参数index(索引)是指明从数组中的第几个对象开始复制.
相信到这里.应该很容易理解CopyTo()和Clone().下面说说浅拷贝和深拷贝的区别.
如上面所说的,浅拷贝对于值类型则复制值,对于引用类型则复制对象的引用(类似于指针).深拷贝则是完完全全的创建一个个新对象.对原来数组中的所有对象全部创建新对象.对新数组中的修改不会影响原来数组中的值或对象.但是如何实现深拷贝呢?.NET库中似乎没有深拷贝的方法.这和实现深拷贝的原理有关系.若用户希望实现深拷贝.希望出现两个完全一样但又互不影响的数组.则必须自己写方法,对原数组中的每个对象实现拷贝,层层深入,直到这个对象中的对象中的对象……中的对象为值类型为止,因为只有值类型才是完全拷贝,对一个值进行修改不会影响另一个相同的值.这么说又有点难理解了.实现深拷贝的方法,如下图:
图中,蓝色代表值类型,直接copy,而红色代表引用类型,需要层层深入直到最后一层是复制值类型为止(这个图画得欠雅观,不过基本表达了深拷贝的原理).
总结
1 都是浅拷贝
2 都是拷贝所有的source到destination
3 copyto的destination是实例化的,而clone的destination必须是实例化的。
using System;
public class SamplesArray
{
public static void Main()
{
// Creates and initializes two new Arrays.
Array mySourceArray = Array.CreateInstance(typeof(String), 6);
mySourceArray.SetValue("three", 0);
mySourceArray.SetValue("napping", 1);
mySourceArray.SetValue("cats", 2);
mySourceArray.SetValue("in", 3);
mySourceArray.SetValue("the", 4);
mySourceArray.SetValue("barn", 5);
Array myTargetArray;
//Array myTargetArray = Array.CreateInstance(typeof(String), 15);
//myTargetArray.SetValue("The", 0);
//myTargetArray.SetValue("quick", 1);
//myTargetArray.SetValue("brown", 2);
//myTargetArray.SetValue("fox", 3);
//myTargetArray.SetValue("jumps", 4);
//myTargetArray.SetValue("over", 5);
//myTargetArray.SetValue("the", 6);
//myTargetArray.SetValue("lazy", 7);
//myTargetArray.SetValue("dog", 8);
// Displays the values of the Array.
//Console.WriteLine("The target Array contains the following (before and after copying):");
//PrintValues(myTargetArray, ' ');
// Copies the source Array to the target Array, starting at index 6.
//mySourceArray.CopyTo(myTargetArray, 6); //这里是编译不过去的,因为CopyTo要求destination必须实例化
myTargetArray = (string[])mySourceArray.Clone(); //没有问题,因为Clone不要求destination必须实例化
// Displays the values of the Array.
PrintValues(myTargetArray, ' ');
Console.ReadLine();
}
public static void PrintValues(Array myArr, char mySeparator)
{
System.Collections.IEnumerator myEnumerator = myArr.GetEnumerator();
int i = 0;
int cols = myArr.GetLength(myArr.Rank - 1);
while (myEnumerator.MoveNext())
{
if (i < cols)
{
i++;
}
else
{
Console.WriteLine();
i = 1;
}
Console.Write("{0}{1}", mySeparator, myEnumerator.Current);
}
Console.WriteLine();
}
}