Diferencia entre System.Array.CopyTo () y System.Array.Clone ()

¿Cuál es la diferencia entre System.Array.CopyTo() y System.Array.Clone() ?

El método Clone () devuelve un nuevo objeto de matriz (una copia superficial) que contiene todos los elementos en la matriz original. El método CopyTo () copia los elementos en otra matriz existente. Ambos realizan una copia superficial. Una copia superficial significa que el contenido (cada elemento de la matriz) contiene referencias al mismo objeto que los elementos en la matriz original. Una copia profunda (que ninguno de estos métodos realiza) crearía una nueva instancia del objeto de cada elemento, dando como resultado un objeto diferente pero idéntico.

Entonces la diferencia es:

 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:

Eliminar el ejemplo incorrecto

Otra diferencia no mencionada hasta ahora es que

  • con Clone() la matriz de destino no debe existir todavía, ya que se crea una nueva desde cero.
  • con CopyTo() no solo es necesario que la matriz de destino ya exista, debe ser lo suficientemente grande como para contener todos los elementos en la matriz fuente del índice que especifique como destino.

Ambos realizan copias superficiales como dijo @PatrickDesjardins (a pesar de las muchas almas engañadas que piensan que CopyTo hace una copia profunda).

Sin embargo, CopyTo permite copiar una matriz a un índice especificado en la matriz de destino, dándole una flexibilidad significativamente mayor.

Como se indica en muchas otras respuestas, ambos métodos realizan copias superficiales de la matriz. Sin embargo, existen diferencias y recomendaciones que aún no se han abordado y que se destacan en las siguientes listas.

Características de System.Array.Clone :

  • Las pruebas, usando .NET 4.0, muestran que es más lento que CopyTo probablemente porque usa Object.MemberwiseClone ;
  • Requiere lanzar el resultado al tipo apropiado;
  • La matriz resultante tiene la misma longitud que la fuente.

Características de System.Array.CopyTo :

  • Es más rápido que Clone cuando se copia a una matriz del mismo tipo;
  • Llama a Array.Copy inheriting es capacidades , siendo las más útiles:
    • Puede encapsular elementos de tipo de valor en elementos de tipo de referencia, por ejemplo, copiar una matriz int[] en un object[] ;
    • Puede unbox referenciar elementos de tipo en elementos de tipo de valor, por ejemplo, copiar una matriz de object[] de int encuadrado en un int[] ;
    • Puede realizar conversiones de ampliación en tipos de valores, por ejemplo, copiar un int[] en un long[] .
    • Puede downcast elements, por ejemplo, copiar una matriz Stream[] en un MemoryStream[] (si cualquier elemento de la matriz fuente no es convertible a MemoryStream se lanza una excepción).
  • Permite copiar la fuente a una matriz de destino que tiene una longitud mayor que la fuente.

También tenga en cuenta que estos métodos están disponibles para admitir ICloneable e ICollection , por lo que si está tratando con variables de tipos de matriz, no debería usar Clone o CopyTo y en su lugar usar Array.Copy o Array.ConstrainedCopy . La copia restringida asegura que si la operación de copia no se puede completar correctamente, entonces el estado de la matriz de destino no está dañado.

 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" 

la fuente

Tanto CopyTo () y Clone () hacen una copia superficial. El método Clone () hace una copia de la matriz original. Devuelve una matriz de longitud exacta.

Por otro lado, CopyTo () copia los elementos de la matriz original a la matriz de destino comenzando en el índice de matriz de destino especificado. Tenga en cuenta que esto agrega elementos a una matriz ya existente.

El siguiente código contradirá las publicaciones que dicen que CopyTo () hace una copia 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); } 

Déjame explicarlo un poco. Si los elementos de la matriz son de tipos de referencia, entonces la copia (tanto para Clone () como CopyTo ()) se realizará hasta el primer nivel (superior). Pero el nivel inferior no se copia. Si también necesitamos una copia del nivel inferior, tenemos que hacerlo explícitamente. Es por eso que después de Clonación o Copia de elementos de tipo de referencia, cada elemento en la matriz Clonado o Copiado se refiere a la misma ubicación de memoria a la que hace referencia el elemento correspondiente en la matriz original. Esto indica claramente que no se crea una instancia separada para el nivel inferior. Y si fuera así, cambiar el valor de cualquier elemento en la matriz copiada o clonada no tendría efecto en el elemento correspondiente de la matriz original.

Creo que mi explicación es exhaustiva, pero no encontré otra manera de hacerlo comprensible.

El método Clone() no da referencia a la instancia de destino solo le da una copia. el método CopyTo() copia los elementos en una instancia existente.

Ambos no dan la referencia de la instancia de destino y como muchos miembros dicen que dan una copia superficial (copia de ilusión) sin referencia, esta es la clave.

Las respuestas son confusas para mí. Cuando dice copia poco profunda, esto significa que todavía están apuntando a la misma dirección. Lo que significa que cambiar cualquiera de los dos cambiará también a otro.

Entonces si tengo A = [1,2,3,4] y lo clono y obtengo B = [1,2,3,4]. Ahora, si cambio B [0] = 9. Esto significa que A ahora será A = [9,2,3,4]. ¿Es eso correcto?

Ambas son copias superficiales. El método CopyTo no es una copia profunda. Compruebe el siguiente 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() se utiliza para copiar solo la estructura de datos / matriz, no copia los datos reales.

CopyTo() copia la estructura y los datos reales.

Tenga en cuenta: existe una diferencia entre usar String [] a StringBuilder [].

En String: si cambia la cadena, las otras matrices que hemos copiado (mediante CopyTo o Clone) que apuntan a la misma cadena no cambiarán, pero la matriz de cadenas original apuntará a una nueva cadena, sin embargo, si usamos un StringBuilder en una matriz, el puntero de cadena no cambiará, por lo tanto, afectará a todas las copias que hemos realizado para esta matriz. Por ejemplo:

 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 }