Unterschied zwischen System.Array.CopyTo () und System.Array.Clone ()

82

Was ist der Unterschied zwischen dem System.Array.CopyTo()und System.Array.Clone()?

Herr Dev
quelle
31
Eine Art dumme Interviewfrage. "Ich erinnere mich nicht ohne weiteres, lassen Sie mich die Dokumentation überprüfen ..."
Cody Gray
@MisterDev Keines dieser Elemente enthält einen Verweis auf das ursprüngliche Array, von dem Sie kopiert haben.
Nyerguds
@Nyerguds Ich denke, er meinte, dass beide Verweise auf die ursprünglichen Array-Elementobjekte behalten, nicht auf das ursprüngliche Array-Objekt selbst.
Reirab
1
@reirab Oh, ich weiß, was er meinte. Aber ich hielt es für notwendig, darauf hinzuweisen, dass er es falsch gesagt hat.
Nyerguds

Antworten:

61

Die Clone () -Methode gibt ein neues Array-Objekt (eine flache Kopie) zurück, das alle Elemente im ursprünglichen Array enthält. Das CopyTo () -Methode kopiert die Elemente in ein anderes vorhandenes Array. Beide führen eine flache Kopie durch. Eine flache Kopie bedeutet, dass der Inhalt (jedes Array-Element) Verweise auf dasselbe Objekt enthält wie die Elemente im ursprünglichen Array. Eine tiefe Kopie (die keine dieser Methoden ausführt) würde eine neue Instanz des Objekts jedes Elements erstellen, was zu einem anderen, aber identischen Objekt führen würde.

Der Unterschied ist also:

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.
Bearbeiten:

Entfernen Sie das falsche Beispiel.

Patrick Desjardins
quelle
6
Ihr Beispiel ist falsch. Im ersten numbersCopyist nur ein weiterer Verweis auf das Array zugeordnet numbers. Dies ist nicht dasselbe wie die Verwendung der CopyTo()Methode. Wenn Sie verwenden CopyTo(), erhalten Sie die gleichen Ergebnisse wie in Ihrem Clone()Beispiel. Auch das ist C # - System.out.printlnsollte sein Console.WriteLine.
Graham Clark
6
Diese Antwort, die wie gesagt irreführend ist , ist eine Kopie von hier: geekswithblogs.net/dforhan/archive/2005/12/01/61852.aspx
Mikhail
Nach dem Beispiel von GenZiy handelt es sich bei beiden um eine flache Kopie. Eine flache Kopie eines Arrays kopiert nur die Elemente des Arrays, unabhängig davon, ob es sich um Referenztypen oder Werttypen handelt, kopiert jedoch nicht die Objekte, auf die sich die Referenzen beziehen. Die Verweise im neuen Array verweisen auf dieselben Objekte, auf die die Verweise im ursprünglichen Array verweisen. Im Gegensatz dazu kopiert eine tiefe Kopie eines Arrays die Elemente und alles, worauf die Elemente direkt oder indirekt verweisen. msdn.microsoft.com/en-us/library/system.array.clone.aspx
Mike
@PatrickDesjardins. Es ist mir nicht sehr klar. Wenn beide eine flache Kopie sind, was ist dann eine tiefe Kopie. Warum CopyTo () eine flache Kopie ist.
KumarHarsh
@KumarHarsh Eine flache Kopie kopiert nur die Verweise auf die Objekte, nicht auf die Objekte selbst. Zum Beispiel, sagen wir mal Sie ein Array hatte arraymit Elementen A, Bund C. Wenn Sie eine flache Kopie davon erstellt arrayund diese geändert haben A, wird die Änderung sowohl im Original als auch in der Kopie angezeigt. Wenn Sie eine tiefe Kopie erstellt hätten, hätten Sie völlig andere Objekte, und dies würde nicht passieren (dies ist leichter zu verstehen, wenn Sie über gute Kenntnisse in Bezug auf Zeiger und Referenzen im Vergleich zu Werten in der Programmierung verfügen).
26

Ein weiterer Unterschied, der bisher nicht erwähnt wurde, ist der folgende

  • mit Clone()dem Ziel-Array muss noch nicht vorhanden sein, da ein neues von Grund auf neu erstellt wird.
  • mit CopyTo()nicht nur entbindet der Ziel - Array bereits existiert, muss es groß genug , um alle Elemente in dem Quell - Array aus dem Index , den Sie als Ziel angeben , zu halten.
Michael Burr
quelle
22

Wie in vielen anderen Antworten angegeben, führen beide Methoden flache Kopien des Arrays durch. Es gibt jedoch Unterschiede und Empfehlungen, die noch nicht angesprochen wurden und die in den folgenden Listen hervorgehoben werden.

Eigenschaften von System.Array.Clone:

  • Tests mit .NET 4.0 zeigen, dass es langsamer ist alsCopyTo wahrscheinlich, weil es verwendet wird Object.MemberwiseClone.
  • Erfordert das Umwandeln des Ergebnisses in den entsprechenden Typ.
  • Das resultierende Array hat die gleiche Länge wie die Quelle.

Eigenschaften von System.Array.CopyTo:

  • Ist schneller alsClone beim Kopieren in ein Array des gleichen Typs;
  • Es Array.Copyerfordert das Erben von Fähigkeiten , die am nützlichsten sind:
    • Kann Werttypelemente in Referenztypelemente einbetten, z. B. das Kopieren eines int[]Arrays in ein object[];
    • Kann Referenztypelemente in Werttypelemente entpacken, z. B. Kopieren eines object[]Arrays von Boxen intin ein int[];
    • Kann erweiterte Konvertierungen für Werttypen durchführen, z. B. das Kopieren von a int[]in a long[].
    • Kann Elemente, einschließlich des Kopierens eines Stream[]Arrays in ein MemoryStream[](wenn ein Element im Quellarray nicht in MemoryStreameine Ausnahme konvertierbar ist, wird ausgelöst).
  • Ermöglicht das Kopieren der Quelle in ein Zielarray mit einer Länge, die größer als die Quelle ist.

Beachten Sie auch , sind diese Verfahren zur Verfügung zu unterstützen ICloneableund ICollection, wenn Sie also mit Variablen von Array - Typen handelt , sollten Sie nicht verwenden Cloneoder CopyTostattdessen verwenden Array.Copyoder Array.ConstrainedCopy. Die eingeschränkte Kopie stellt sicher, dass der Status des Zielarrays nicht beschädigt wird, wenn der Kopiervorgang nicht erfolgreich abgeschlossen werden kann.

João Angelo
quelle
Dies ist eine solide Information. Warum schreiben wir nicht eine schnellere, generische Version von Clone? So etwas wie: Beispiel: public static T [] ExtFastClone <T> (dieses T [] arr) {if (null == arr) {return null; } T [] arr2 = new T [arr.Length]; arr.CopyTo (arr2, 0); return arr2; } Oder Sie könnten eine Casting-Version (um int -> long zuzulassen) wie: public static TOut [] ExtFastClone <TIn, TOut> (dieses TIn [] arr)
kevinarpe
Für das flache Klonen in .NET 3.5 oder höher können Sie einfach die Linq- .ToArray()Methode verwenden. Es erstellt ohnehin eine Kopie und kann auf allen IEnumerable<>Arrays ausgeführt werden , einschließlich Arrays. Und im Gegensatz dazu .Clone()ist es getippt, so dass kein Casting erforderlich ist.
Nyerguds
21

Beide führen flache Kopien durch, wie @PatrickDesjardins sagte (trotz der vielen irregeführten Seelen, die denken, dass CopyTodies eine tiefe Kopie ist).

Sie CopyTokönnen jedoch ein Array in einen angegebenen Index im Zielarray kopieren, wodurch die Flexibilität erheblich erhöht wird.

FlySwat
quelle
8
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"

die Quelle

GenZiy
quelle
1
Ich denke, Shalow-Kopie bedeutet, dass nur Referenzen kopiert werden, kein Wert. Wenn Sie also den Wert von myarray [0] von "eins" auf 0 ändern, sollte der Wert von myarray1 [0] und myarray [1] nicht ebenfalls 0 sein.
Adarsh ​​Kumar
1
Entschuldigung, aber Ihre Vermutung ist falsch. Eine flache Kopie ist keine Kopie von Referenzen: "Die MemberwiseClone-Methode erstellt eine flache Kopie, indem sie ein neues Objekt erstellt und dann die nicht statischen Felder des aktuellen Objekts in das neue Objekt kopiert." siehe msdn.microsoft.com/en-us/library/…
GenZiy
1
Flache oder tiefe Kopien sind irrelevant, wenn die Typen, die Sie in Ihr Array einfügen, primitiv / unveränderlich sind . Zeichenfolgen und Ganzzahlen erzeugen immer eine neue Kopie, wenn sie in etwas anderes eingefügt werden. Platzieren Sie zum Testen der Tiefenkopie ein komplexes Objekt (wie ein Array) an einer der Stellen.
Nyerguds
2

Sowohl CopyTo () als auch Clone () erstellen eine flache Kopie. Die Clone () -Methode erstellt einen Klon des ursprünglichen Arrays. Es wird ein Array mit exakter Länge zurückgegeben.

Andererseits kopiert CopyTo () die Elemente aus dem ursprünglichen Array in das Zielarray, beginnend mit dem angegebenen Zielarrayindex. Beachten Sie, dass dadurch Elemente zu einem bereits vorhandenen Array hinzugefügt werden.

Der folgende Code widerspricht den Postings, die besagen, dass CopyTo () eine tiefe Kopie erstellt:

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);
}

Lassen Sie es mich ein wenig erklären. Wenn die Elemente des Arrays vom Referenztyp sind, wird die Kopie (sowohl für Clone () als auch für CopyTo ()) bis zur ersten (obersten) Ebene erstellt. Die untere Ebene wird jedoch nicht kopiert. Wenn wir auch eine Kopie der unteren Ebene benötigen, müssen wir dies explizit tun. Aus diesem Grund verweist nach dem Klonen oder Kopieren von Elementen vom Referenztyp jedes Element im geklonten oder kopierten Array auf denselben Speicherort, auf den sich das entsprechende Element im ursprünglichen Array bezieht. Dies zeigt deutlich an, dass keine separate Instanz für eine niedrigere Ebene erstellt wurde. Wenn dies der Fall wäre, hätte das Ändern des Werts eines Elements im kopierten oder geklonten Array keine Auswirkungen auf das entsprechende Element des ursprünglichen Arrays.

Ich denke, meine Erklärung ist erschöpfend, aber ich habe keinen anderen Weg gefunden, sie verständlich zu machen.

Prasad
quelle
1

Array.Clone()würde eine technisch tiefe Kopie durchführen, wenn das Array intoder die Zeichenfolge als Referenz an eine Methode übergeben wird.

Beispielsweise

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

Selbst wenn die Methoden das Zahlenarray sortieren, dies jedoch keinen Einfluss auf die tatsächliche Referenz hat, die an die Sortiermethoden übergeben wird. Das Zahlenarray hat in Zeile 1 das gleiche unsortierte Anfangsformat.

Hinweis: Das Klonen sollte in den Sortiermethoden erfolgen.

Umasankar Siva
quelle
0

Die Clone()Methode gibt keinen Verweis auf die Zielinstanz, sondern gibt Ihnen nur eine Kopie. Die CopyTo()Methode kopiert die Elemente in eine vorhandene Instanz.

Beide geben nicht die Referenz der Zielinstanz an und da viele Mitglieder sagen, dass sie eine flache Kopie (Illusionskopie) ohne Referenz geben, ist dies der Schlüssel.

Mohammad Ahmed
quelle
0

Die Antworten sind für mich verwirrend. Wenn Sie flache Kopie sagen, bedeutet dies, dass sie immer noch auf dieselbe Adresse zeigen. Das heißt, wenn Sie eines der beiden ändern, ändert sich auch das andere.

Wenn ich also A = [1,2,3,4] habe und es klone und B = [1,2,3,4] erhalte. Wenn ich nun B [0] = 9 ändere, bedeutet dies, dass A jetzt A = [9,2,3,4] ist. Ist das korrekt?

Fremder
quelle
Nein. Wenn wir den Wert des b-Arrays ändern, wirkt sich dies nur auf das b-Array aus. nicht das A-Array.
Gomathipriya
Ganzzahlen, Zeichenfolgen, Datumsangaben usw. werden niemals durch Verweise kopiert, Personen . Flach bedeutet "nur eine Ebene tief". Dies bedeutet, dass Referenztypen (Arrays oder andere komplexe Objekte) weiterhin auf dieselben Objekte verweisen. Nicht primitive / unveränderliche Typen; Diese sind so konzipiert, dass sie niemals als Referenz verwendet werden.
Nyerguds
Flache Kopien gelten nur für komplexe Objekte wie Strukturen, Zeichenfolgen, Listen usw. Ein Int- oder Double-Array enthält immer eine tiefe Kopie.
Zuabros
0

Beide sind flache Kopien. Die CopyTo-Methode ist keine tiefe Kopie. Überprüfen Sie den folgenden 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 */
Nikhil Redij
quelle
0

Für Array.Clone muss beim Aufrufen der Funktion kein Ziel- / Zielarray verfügbar sein, während für Array.CopyTo ein Zielarray und ein Index erforderlich sind.

Aikansh Mann
quelle
-1

Clone() wird verwendet, um nur die Struktur von Daten / Arrays zu kopieren. Es werden nicht die tatsächlichen Daten kopiert.

CopyTo() kopiert die Struktur sowie die tatsächlichen Daten.

abatishchev
quelle
-2

Bitte beachten Sie: Es gibt einen Unterschied zwischen der Verwendung von String [] und StringBuilder [].

In String - Wenn Sie den String ändern, ändern sich die anderen Arrays, die wir kopiert haben (von CopyTo oder Clone) und die auf denselben String verweisen, nicht. Das ursprüngliche String-Array zeigt jedoch auf einen neuen String, wenn wir einen StringBuilder verwenden In einem Array ändert sich der String-Zeiger nicht. Daher wirkt er sich auf alle Kopien aus, die wir für dieses Array erstellt haben. Zum Beispiel:

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
}
inbaly
quelle
1
Dies hat nichts mit CopyTovs zu tun Clone. Es ist nur Referenzsemantik gegen Wertesemantik. int ist ein Werttyp, sodass Sie jedes Mal eine neue Kopie erhalten. StringBuilder verfügt über eine Referenzsemantik, sodass Sie auf dieselbe Kopie reagieren.
Nawfal
@nawfal - Ich weiß, deshalb habe ich 'Bitte beachten' geschrieben ... es gibt einen Unterschied im Verhalten zwischen String, StringBuilder und int in copyto und clone, und es kann für jemanden verwirrend sein, der sich dessen nicht bewusst ist.
Inbaly