Разница между System.Array.CopyTo () и System.Array.Clone ()

В чем разница между System.Array.CopyTo() и System.Array.Clone()?

Типа тупой вопрос на собеседовании. «Навскидку не припомню, дай проверить документацию ...»

Cody Gray 13.02.2012 13:03

@MisterDev Ни один из них не будет содержать ссылки на исходный массив, из которого вы скопировали, нет.

Nyerguds 28.11.2016 12:51

@Nyerguds Я думаю, он имел в виду, что они оба хранят ссылки на исходные объекты элементов массива, а не на сам исходный объект массива.

reirab 15.12.2016 20:38

@reirab О, я понимаю, что он имел в виду. Но я счел необходимым указать, что он сказал это неправильно.

Nyerguds 16.12.2016 21:55
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
86
4
107 280
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Ответ принят как подходящий

Метод Клонировать () возвращает новый объект массива (неглубокую копию), содержащий все элементы исходного массива. Метод Скопировать в() копирует элементы в другой существующий массив. Оба выполняют неглубокую копию. Неглубокая копия означает, что содержимое (каждый элемент массива) содержит ссылки на тот же объект, что и элементы в исходном массиве. Глубокая копия (которую не выполняет ни один из этих методов) создаст новый экземпляр объекта каждого элемента, в результате чего получится другой, но идентичный объект.

Итак, разница в следующем:

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

Удалите неправильный пример.

Ваш пример неверен. В первом numbersCopy - это просто еще одна ссылка на массив, назначенный numbers. Это нет то же самое, что и при использовании метода CopyTo(). Если вы используете CopyTo(), вы получите те же результаты, что и в вашем примере Clone(). Кроме того, это C# - System.out.println должен быть Console.WriteLine.

Graham Clark 02.09.2010 14:43

Этот ответ, который, как говорили другие, вводящий в заблуждение, является копипастом отсюда: geekswithblogs.net/dforhan/archive/2005/12/01/61852.aspx

Mikhail 08.11.2011 11:29

По примеру GenZiy, оба они - неглубокая копия. Неглубокая копия массива копирует только элементы массива, независимо от того, являются ли они ссылочными типами или типами значений, но не копирует объекты, на которые ссылаются ссылки. Ссылки в новом массиве указывают на те же объекты, на которые указывают ссылки в исходном массиве. Напротив, глубокая копия массива копирует элементы и все, на что прямо или косвенно ссылаются элементы. msdn.microsoft.com/en-us/library/system.array.clone.aspx

Mike 30.10.2013 01:33

@PatrickDesjardins. Мне не очень понятно. Если оба являются мелкой копией, то что такое глубокая копия. Почему CopyTo () - это мелкая копия.

KumarHarsh 02.06.2014 13:18

@KumarHarsh Мелкая копия просто копирует использованная литература в объекты, а не сами объекты. Например, предположим, что у вас есть массив array с элементами A, B и C. Если вы сделали неглубокую копию array и модифицировали в ней A, изменение будет видно как в оригинале, так и в копии. Если бы вы сделали глубокую копию, у вас были бы совершенно другие объекты, и этого бы не произошло (это легче понять, если вы хорошо разбираетесь в указателях и ссылках на значения в программировании).

user837703 30.07.2014 06:15

В .Net 3.5 метод Linq ToArray() в любом случае предоставляет гораздо более простой (и напечатанный) способ поверхностного клонирования массива. Поскольку массив - IENumerable<T>, он работает с ним.

Nyerguds 28.11.2016 12:28

Большое спасибо, очень подробно

Samantha Jones 24.01.2019 13:11

Оба выполняют мелкие копии, как сказал @PatrickDesjardins (несмотря на многие заблуждающиеся души, которые думают, что CopyTo делает глубокую копию).

Однако CopyTo позволяет копировать один массив в указанный индекс в целевом массиве, что дает ему значительно большую гибкость.

Еще одно отличие, не упомянутое до сих пор, заключается в том, что

  • с Clone() целевой массив еще не должен существовать, поскольку новый создается с нуля.
  • с 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"

источник

Полагаю, неглубокая копия означает, что копируются только ссылки, а не значения. Таким образом, если вы меняете значение myarray [0] с «единицы» на 0, тогда значение myarray 1 [0] и myarray [1] также не должно быть 0.

Adarsh Kumar 13.03.2014 15:06

Извините, но ваше предположение неверно. Неглубокая копия не является копией ссылок: «Метод MemberwiseClone создает неглубокую копию, создавая новый объект, а затем копируя нестатические поля текущего объекта в новый объект». см. msdn.microsoft.com/en-us/library/…

GenZiy 26.03.2014 03:52

Мелкая или глубокая копия - не имеет значения, если типы, которые вы помещаете в свой массив, примитивны / неизменны. Строки и целые числа всегда создают новую копию, когда помещаются во что-то еще. Чтобы проверить глубокую копию, поместите сложный объект (например, массив) в одно из мест.

Nyerguds 28.11.2016 12:36

Clone() используется для копирования только структуры данных / массива, он не копирует фактические данные.

CopyTo() копирует структуру, а также фактические данные.

И 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 ()) будет сделана до первого (верхнего) уровня. Но нижний уровень не копируется. Если нам также нужна копия нижнего уровня, мы должны сделать это явно. Вот почему после клонирования или копирования элементов ссылочного типа каждый элемент в клонированном или скопированном массиве ссылается на ту же ячейку памяти, на которую ссылается соответствующий элемент в исходном массиве. Это ясно указывает на то, что отдельный экземпляр не создается для более низкого уровня. И если бы это было так, то изменение значения любого элемента в скопированном или клонированном массиве не повлияло бы на соответствующий элемент исходного массива.

Я думаю, что мое объяснение исчерпывающее, но я не нашел другого способа сделать его понятным.

Метод Clone() не дает ссылку на целевой экземпляр, а просто предоставляет вам копию. метод CopyTo() копирует элементы в существующий экземпляр.

Оба не дают ссылку на целевой экземпляр, и, поскольку многие участники говорят, что они дают неглубокую копию (иллюзию копии) без ссылки, это ключ.

Как указано во многих других ответах, оба метода выполняют мелкие копии массива. Однако есть различия и рекомендации, которые еще не рассмотрены и выделены в следующих списках.

Характеристики System.Array.Clone:

  • Тесты с использованием .NET 4.0 показывают, что это медленнее, чем 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. Ограниченная копия гарантирует, что если операция копирования не может завершиться успешно, то состояние целевого массива не повреждено.

Это достоверная информация. Так почему бы нам не написать более быструю универсальную версию Clone? Что-то вроде: Пример: public static T [] ExtFastClone <T> (this T [] arr) {if (null == arr) {return null; } T [] arr2 = новый T [arr.Length]; arr.CopyTo (arr2, 0); return arr2; } Или вы можете сделать версию приведения (чтобы разрешить int -> long), например: public static TOut [] ExtFastClone <TIn, TOut> (this TIn [] arr)

kevinarpe 10.12.2012 14:58

Для поверхностного клонирования в .Net 3.5 или выше вы можете просто использовать метод Linq .ToArray(). Он все равно делает копию, и ее можно запускать на любом IEnumerable<>, включая массивы. И, в отличие от .Clone(), он типизирован, поэтому преобразование не требуется.

Nyerguds 28.11.2016 12:31

Ответы меня сбивают с толку. Когда вы говорите «неглубокая копия», это означает, что они по-прежнему указывают на тот же адрес. Это означает, что изменение одного из них изменит и другое.

Итак, если у меня есть A = [1,2,3,4], я клонирую его и получаю B = [1,2,3,4]. Теперь, если я изменю B [0] = 9. Это означает, что теперь A будет A = [9,2,3,4]. Это верно?

нет. если мы изменим значение массива b, это повлияет только на этот массив b. не массив A.

Gomathipriya 17.09.2013 09:59

Целые числа, строки, даты и т. д. никогда не копируйте по ссылке, люди. Shallow означает «только на один уровень глубиной». Это означает, что типы Справка (массивы или другие сложные объекты) по-прежнему будут указывать на одни и те же объекты. Не примитивные / неизменяемые типы; они разработаны, чтобы никогда не использоваться в качестве ссылок.

Nyerguds 28.11.2016 12:43

Неглубокие копии применяются только к сложным объектам, таким как структуры, строки, списки и т. д. Массив Int или double всегда будет иметь глубокую копию.

Zuabros 13.08.2020 14:35

Обратите внимание: существует разница между использованием 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 имеет ссылочную семантику, поэтому вы работаете с одной и той же копией.

nawfal 09.12.2013 17:28

@nawfal - я знаю, именно поэтому я написал «обратите внимание» ... есть разница в поведении между String, StringBuilder и int, в copyto и clone, и это может сбивать с толку тех, кто не знает об этом.

inbaly 23.04.2014 11:51

Оба являются мелкими копиями. 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.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.

Примечание: Клонирование должно выполняться в методах сортировки.

Другие вопросы по теме