В чем разница между 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[]
в long[]
.Stream[]
массив в MemoryStream[]
(если какой-либо элемент в исходном массиве не может быть преобразован в MemoryStream
исключение).Также обратите внимание, что эти методы доступны для поддержки ICloneable
и ICollection
, поэтому, если вы имеете дело с переменными типов массивов, вам не следует использовать Clone
или, CopyTo
а вместо этого использовать Array.Copy
или Array.ConstrainedCopy
. Ограниченная копия гарантирует, что если операция копирования не может завершиться успешно, то состояние целевого массива не повреждено.
.ToArray()
метод Linq . Он все равно делает копию, и ее можно запускать на любом IEnumerable<>
, включая массивы. И, в отличие от .Clone()
, он типизирован, поэтому не требует преобразования.
Оба выполняют неглубокие копии, как сказал @PatrickDesjardins (несмотря на множество заблуждающихся душ, которые думают, что это CopyTo
делает глубокую копию).
Однако CopyTo
позволяет копировать один массив в указанный индекс в целевом массиве, что дает ему значительно большую гибкость.
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 [].
В String - если вы измените String, другие массивы, которые мы скопировали (с помощью 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 имеет ссылочную семантику, поэтому вы работаете с одной и той же копией.