Яка різниця між System.Array.CopyTo()
і System.Array.Clone()
?
Яка різниця між System.Array.CopyTo()
і System.Array.Clone()
?
Відповіді:
Метод 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
.
ToArray()
метод Linq надає набагато простіший (і набраний ) спосіб дрібного клонування масиву в будь-якому випадку. Оскільки Array IENumerable<T>
це працює на ньому.
Ще одна відмінність, про яку до цього часу не згадується, полягає в тому,
Clone()
цільовим масивом ще не потрібно існувати, оскільки новий створюється з нуля.CopyTo()
не тільки необхідність масив призначення вже існує, він повинен бути досить великим , щоб вмістити всі елементи в вихідному масиві з індексу ви вказуєте в якості пункту призначення.Як зазначено в багатьох інших відповідях, обидва методи виконують неглибокі копії масиву. Однак існують розбіжності та рекомендації, які ще не були розглянуті і які виділено в наступних списках.
Характеристики System.Array.Clone
:
CopyTo
можливо, тому, що він використовує Object.MemberwiseClone
;Характеристики System.Array.CopyTo
:
Clone
при копіюванні в масив того ж типу;Array.Copy
успадкування можливостей , які є найбільш корисними:
int[]
масив у файл object[]
;object[]
масив, введений int
у поле int[]
;int[]
в a long[]
.Stream[]
масив в MemoryStream[]
(якщо будь-який елемент у вихідному масиві не конвертований у MemoryStream
виняток).Також зверніть увагу, що ці методи доступні для підтримки ICloneable
і ICollection
, таким чином , якщо ви маєте справу зі змінними типів масивів , ви не повинні використовувати Clone
або CopyTo
і натомість використовувати Array.Copy
або Array.ConstrainedCopy
. Обмежена копія гарантує, що якщо операція копіювання не може завершитися успішно, стан цільового масиву не пошкоджений.
.ToArray()
методом Лінка . Він робить копію в будь-якому випадку і може бути виконаний на будь-якому IEnumerable<>
, включаючи масиви. І на відміну від цього .Clone()
, він набраний, тому кастинг не потрібен.
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"
І 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 ()) буде виконана на перший (верхній) рівень. Але нижній рівень не копіюється. Якщо нам потрібна також копія нижчого рівня, ми повинні робити це явно. Ось чому після Клонування або Копіювання елементів довідкового типу кожен елемент у масиві Клонований або Скопійований посилається на те саме розташування пам’яті, що і відповідний елемент у вихідному масиві. Це чітко вказує на те, що для нижчого рівня не створюється окремий екземпляр. І якби це було так, тоді зміна значення будь-якого елемента в скопійованому або клонованому масиві не мало б ефекту у відповідному елементі вихідного масиву.
Я думаю, що моє пояснення вичерпне, але я не знайшов іншого способу зробити це зрозумілим.
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.
Примітка: Клонування слід виконувати методами сортування.
Clone()
Метод не дає посилання на цільовому екземпляр просто дати вам копію. то CopyTo()
метод копіює елементи в існуючий екземпляр.
Обидва не дають посилання на цільовий екземпляр, і, як багато учасників кажуть, вони дають поверхневу копію (ілюзійну копію) без посилання, це ключ.
Відповіді мене бентежать. Коли ви кажете неглибоку копію, це означає, що вони все ще вказують на ту саму адресу. А це означає, що зміна одного з них змінить і іншого.
Отже, якщо у мене A = [1,2,3,4], і я клоную його і отримую B = [1,2,3,4]. Тепер, якщо я зміню B [0] = 9. Це означає, що A тепер буде A = [9,2,3,4]. Це правильно?
Обидва - неглибокі копії. Метод 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 */
Array.Clone не вимагає наявності цільового / цільового масиву під час виклику функції, тоді як Array.CopyTo вимагає масиву призначення та індексу.
Зверніть увагу: Існує різниця між використанням String [] та StringBuilder [].
У рядку - якщо ви зміните рядок, інші скопійовані нами масиви (за допомогою CopyTo або Clone), що вказує на ту саму рядок, не зміняться, але оригінальний масив 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 має посилальну семантику, тому ви дієте на одній копії.