Jaka jest różnica między System.Array.CopyTo()
i System.Array.Clone()
?
Jaka jest różnica między System.Array.CopyTo()
i System.Array.Clone()
?
Odpowiedzi:
Metoda Clone () zwraca obiekt nowej tablicy (płytkiej kopii) zawierający wszystkie elementy oryginalnej tablicy. Metoda CopyTo () kopiuje elementy do innej istniejącej tablicy. Obaj wykonują płytką kopię. Płytka kopia oznacza, że zawartość (każdy element tablicy) zawiera odniesienia do tego samego obiektu, co elementy oryginalnej tablicy. Głęboka kopia (której żadna z tych metod nie wykonuje) utworzyłaby nowe wystąpienie obiektu każdego elementu, co spowodowałoby inny, ale identyczny obiekt.
Więc różnica jest taka:
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.
Edytować:
Usuń zły przykład.
numbersCopy
jest po prostu kolejnym odwołaniem do tablicy przypisanej do numbers
. To nie to samo, co użycie CopyTo()
metody. Jeśli użyjesz CopyTo()
, uzyskasz takie same wyniki, jak w swoim Clone()
przykładzie. Również to jest C # - System.out.println
powinno być Console.WriteLine
.
ToArray()
metoda Linq zapewnia znacznie prostszy (i wpisany typowo ) sposób płytkiego klonowania tablicy. Ponieważ Array IENumerable<T>
to działa na nim.
Jeszcze jedna różnica, o której do tej pory nie wspomniano, to to
Clone()
tablicą docelową nie musi jeszcze istnieć, ponieważ nowa jest tworzona od podstaw.CopyTo()
nie tylko konieczność przeznaczenia na tablicy już istnieje, to musi być wystarczająco duży, aby pomieścić wszystkie elementy w tablicy źródłowej z indeksu można określić jako miejsce docelowe.Jak stwierdzono w wielu innych odpowiedziach, obie metody wykonują płytkie kopie tablicy. Istnieją jednak różnice i zalecenia, które nie zostały jeszcze uwzględnione i które zostały podkreślone na poniższych listach.
Charakterystyka System.Array.Clone
:
CopyTo
prawdopodobnie dlatego, że używa Object.MemberwiseClone
;Charakterystyka System.Array.CopyTo
:
Clone
przy kopiowaniu do tablicy tego samego typu;Array.Copy
dziedziczenia możliwości , które są najbardziej przydatne:
int[]
tablicy do object[]
;object[]
tablicy pudełek int
do int[]
;int[]
do long[]
.Stream[]
tablicy do MemoryStream[]
(jeśli którykolwiek element w tablicy źródłowej nie jest konwertowany na MemoryStream
wyjątek).Należy również pamiętać, metody te są udostępniane w celu wspierania ICloneable
i ICollection
, więc jeśli masz do czynienia ze zmiennymi typów tablicowych nie należy używać Clone
albo CopyTo
i zamiast używać Array.Copy
lub Array.ConstrainedCopy
. Ograniczona kopia zapewnia, że jeśli operacja kopiowania nie może zakończyć się pomyślnie, stan tablicy docelowej nie jest uszkodzony.
.ToArray()
metody Linq . Mimo to tworzy kopię i można ją wykonać na dowolnej IEnumerable<>
, w tym na tablicach. W przeciwieństwie do .Clone()
tego jest wpisany na maszynie, więc nie jest potrzebne przesyłanie.
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"
Zarówno CopyTo (), jak i Clone () tworzą powierzchowną kopię. Metoda Clone () tworzy klon oryginalnej tablicy. Zwraca tablicę o dokładnej długości.
Z drugiej strony CopyTo () kopiuje elementy z oryginalnej tablicy do tablicy docelowej, zaczynając od określonego indeksu tablicy docelowej. Zauważ, że dodaje to elementy do już istniejącej tablicy.
Poniższy kod zaprzecza postom mówiącym, że CopyTo () tworzy głęboką kopię:
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);
}
Pozwól, że trochę to wyjaśnię. Jeśli elementy tablicy są typu referencyjnego, kopia (zarówno dla Clone (), jak i CopyTo ()) zostanie utworzona do pierwszego (najwyższego) poziomu. Ale niższy poziom nie jest kopiowany. Jeśli potrzebujemy również kopii niższego poziomu, musimy to zrobić wyraźnie. Dlatego po klonowaniu lub kopiowaniu elementów typu referencyjnego każdy element w tablicy sklonowanej lub skopiowanej odnosi się do tej samej lokalizacji pamięci, do której odnosi się odpowiedni element w oryginalnej tablicy. To wyraźnie wskazuje, że nie jest tworzona osobna instancja dla niższego poziomu. Gdyby tak było, zmiana wartości dowolnego elementu w tablicy skopiowanej lub sklonowanej nie wpłynęłaby na odpowiedni element oryginalnej tablicy.
Myślę, że moje wyjaśnienie jest wyczerpujące, ale nie znalazłem innego sposobu, aby było zrozumiałe.
Array.Clone()
wykonałby technicznie głęboką kopię, gdy przekazał tablicę int
lub ciąg do metody jako odniesienie.
Na przykład
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
Nawet jeśli metody sortują tablicę liczb, ale nie wpłynie to na rzeczywistą referencję przekazaną do metod sortowania. Tj. Tablica liczb będzie w tym samym nieposortowanym formacie początkowym w wierszu nr 1.
Uwaga: Klon należy wykonać w metodach sortowania.
Clone()
Metoda nie dać odwołanie do instancji docelowej po prostu dać ci kopię. te CopyTo()
metody kopiuje elementów w istniejącym przykład.
Oba nie podają odniesienia do instancji docelowej i jak wielu członków twierdzi, że podaje płytką kopię (kopię iluzji) bez odniesienia, to jest klucz.
Odpowiedzi są dla mnie mylące. Kiedy mówisz płytka kopia, oznacza to, że nadal wskazują ten sam adres. Co oznacza, że zmiana jednego z nich spowoduje również zmianę innego.
Więc jeśli mam A = [1,2,3,4] i sklonuję go i otrzymam B = [1,2,3,4]. Teraz, jeśli zmienię B [0] = 9. To oznacza, że A będzie teraz A = [9,2,3,4]. Czy to jest poprawne?
Oba są płytkimi kopiami. CopyTo nie jest głęboką kopią. Sprawdź poniższy kod:
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 */
Array.Clone nie wymaga, aby tablica docelowa / docelowa była dostępna podczas wywoływania funkcji, podczas gdy Array.CopyTo wymaga tablicy docelowej i indeksu.
Clone()
służy do kopiowania tylko struktury danych / tablicy, nie kopiuje rzeczywistych danych.
CopyTo()
kopiuje strukturę oraz aktualne dane.
Uwaga: istnieje różnica między używaniem String [] do StringBuilder [].
W String - jeśli zmienisz String, inne tablice, które skopiowaliśmy (przez CopyTo lub Clone), które wskazują na ten sam ciąg, nie ulegną zmianie, ale oryginalna tablica String będzie wskazywać na nowy String, jednak jeśli użyjemy StringBuilder w tablicy wskaźnik String nie ulegnie zmianie, dlatego wpłynie to na wszystkie kopie, które utworzyliśmy dla tej tablicy. Na przykład:
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
vs Clone
. To tylko semantyka referencyjna a semantyka wartości. int jest typem wartości, więc za każdym razem otrzymujesz nową kopię. StringBuilder ma semantykę odwołań, więc działasz na tej samej kopii.