Diferença entre o System.Array.CopyTo () e System.Array.Clone ()

Qual é a diferença entre o System.Array.CopyTo() e System.Array.Clone() ?

O método Clone () retorna um novo object de matriz (uma cópia superficial) contendo todos os elementos da matriz original. O método CopyTo () copia os elementos para outro array existente. Ambos executam uma cópia superficial. Uma cópia superficial significa que o conteúdo (cada elemento da matriz) contém referências ao mesmo object que os elementos da matriz original. Uma cópia profunda (que nenhum desses methods executa) criaria uma nova instância do object de cada elemento, resultando em um object diferente, mas idêntico.

Então a diferença é:

 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. 

Editar:

Remova o exemplo errado.

Uma outra diferença não mencionada até agora é que

  • com Clone() a matriz de destino ainda não precisa existir, uma vez que uma nova é criada do zero.
  • com CopyTo() não apenas a matriz de destino precisa existir, ela precisa ser grande o suficiente para conter todos os elementos na matriz de origem do índice especificado como o destino.

Ambos realizam cópias superficiais, como disse @PatrickDesjardins (apesar das muitas almas enganadas que pensam que o CopyTo faz uma cópia profunda).

No entanto, o CopyTo permite que você copie um array para um índice especificado no array de destino, dando-lhe uma flexibilidade significativamente maior.

Como afirmado em muitas outras respostas, ambos os methods realizam cópias superficiais da matriz. No entanto, existem diferenças e recomendações que ainda não foram abordadas e estão destacadas nas listas a seguir.

Características de System.Array.Clone :

  • Testes, usando o .NET 4.0, mostram que é mais lento que CopyTo provavelmente porque ele usa Object.MemberwiseClone ;
  • Requer a conversão do resultado para o tipo apropriado;
  • O array resultante tem o mesmo comprimento que a fonte.

Características de System.Array.CopyTo :

  • É mais rápido que o Clone ao copiar para um array do mesmo tipo;
  • Chama Array.Copy herdando é capacidades , sendo as mais úteis:
    • Pode agrupar elementos de tipo de valor em elementos de tipo de referência, por exemplo, copiar uma matriz int[] em um object[] ;
    • Pode unbox elementos de tipo de referência em elementos de tipo de valor, por exemplo, copiando uma matriz de object[] de int checkbox em um int[] ;
    • Pode realizar ampliações de conversões em tipos de valor, por exemplo, copiar um int[] em um long[] .
    • Os elementos de downcast podem, por exemplo, copiar uma matriz Stream[] em um MemoryStream[] (se algum elemento na matriz de origem não for convertível em MemoryStream uma exceção será lançada).
  • Permite copiar a fonte para uma matriz de destino que tenha um comprimento maior que a origem.

Observe também que esses methods são disponibilizados para suportar ICloneable e ICollection , portanto, se você estiver lidando com variables ​​de tipos de matriz, não deverá usar Clone ou CopyTo e, em vez disso, usar Array.Copy ou Array.ConstrainedCopy . A cópia restrita assegura que, se a operação de cópia não puder ser concluída com êxito, o estado da matriz de destino não estará corrompido.

 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" 

a fonte

CopyTo () e Clone () fazem cópia superficial. O método Clone () faz um clone da matriz original. Retorna um array de comprimento exato.

Por outro lado, CopyTo () copia os elementos da matriz original para a matriz de destino, iniciando no índice de matriz de destino especificado. Observe que isso adiciona elementos a uma matriz já existente.

O código a seguir irá contradizer as postagens dizendo que CopyTo () faz uma cópia profunda:

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

Deixe-me explicar um pouco. Se os elementos da matriz forem de tipos de referência, a cópia (para Clone () e CopyTo ()) será feita até o primeiro nível (superior). Mas o nível inferior não é copiado. Se precisarmos de cópia de nível inferior também, temos que fazê-lo explicitamente. É por isso que, após Clonagem ou Cópia de elementos de tipo de referência, cada elemento na matriz Clonada ou Copiada refere-se à mesma localização de memory conforme referido pelo elemento correspondente na matriz original. Isso indica claramente que nenhuma instância separada é criada para o nível inferior. E se fosse assim, alterar o valor de qualquer elemento na matriz Copiada ou Clonada não teria efeito no elemento correspondente da matriz original.

Acho que minha explicação é exaustiva, mas não encontrei outra maneira de torná-la compreensível.

O método Clone() não fornece referência à instância de destino, apenas fornece uma cópia. o método CopyTo() copia os elementos em uma instância existente.

Ambos não fornecem a referência da instância de destino e, como muitos membros dizem que fornecem uma cópia superficial (cópia de ilusão) sem referência, essa é a chave.

As respostas são confusas para mim. Quando você diz cópia superficial, isso significa que eles ainda estão apontando para o mesmo endereço. O que significa que mudar qualquer um também mudará outro.

Então, se eu tiver A = [1,2,3,4], clonei e obtive B = [1,2,3,4]. Agora, se eu mudar B [0] = 9. Isso significa que A será agora A = [9,2,3,4]. Isso está correto?

Ambas são cópias rasas. O método CopyTo não é uma cópia profunda. Verifique o seguinte código:

 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 */ 

Clone() é usado para copiar apenas a estrutura de dados / array que não copia os dados reais.

CopyTo() copia a estrutura, bem como os dados reais.

Por favor note: Existe uma diferença entre usar String [] para StringBuilder [].

Em String – se você alterar a String, as outras matrizes copiadas (por CopyTo ou Clone) que apontam para a mesma string não serão alteradas, mas a matriz String original apontará para uma nova String, no entanto, se usarmos um StringBuilder em uma matriz, o ponteiro String não será alterado, portanto, afetará todas as cópias que fizemos para essa matriz. Por exemplo:

 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 }