1. 程式人生 > >C#陣列中CopyTo()和Clone()的區別(轉)

C#陣列中CopyTo()和Clone()的區別(轉)

有很多初學者會對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();
    }
}