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

82

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

Señor Dev
fuente
31
Una especie de pregunta tonta de la entrevista. "No lo recuerdo de improviso, déjame comprobar la documentación ..."
Cody Gray
@MisterDev Ninguno de estos mantendrá ninguna referencia a la matriz original desde la que copió, no.
Nyerguds
@Nyerguds Creo que quiso decir que ambos mantienen referencias a los objetos del elemento de matriz original, no al objeto de matriz original en sí.
reirab
1
@reirab Oh, soy consciente de lo que quiso decir. Pero sentí necesario señalar que lo dijo mal.
Nyerguds

Respuestas:

63

El método Clone () devuelve un nuevo objeto de matriz (una copia superficial) que contiene todos los elementos de 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 de la matriz original. Una copia profunda (que no realiza ninguno de estos métodos) 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:

Elimine el ejemplo incorrecto.

Patrick Desjardins
fuente
6
Tu ejemplo está mal. En el primero, numbersCopyes solo otra referencia al arreglo asignado a numbers. Esto no es lo mismo que usar el CopyTo()método. Si lo usa CopyTo(), obtendrá los mismos resultados que en su Clone()ejemplo. Además, esto es C #, System.out.printlndebería serlo Console.WriteLine.
Graham Clark
6
Esta respuesta, que es engañosa como dijeron otros, es una copia y pegado de aquí: geekswithblogs.net/dforhan/archive/2005/12/01/61852.aspx
Mikhail
Según el ejemplo de GenZiy, ambos son copias superficiales. Una copia superficial de un Array copia solo los elementos del Array, ya sean tipos de referencia o tipos de valor, pero no copia los objetos a los que hacen referencia las referencias. Las referencias en el nuevo Array apuntan a los mismos objetos a los que apuntan las referencias en el Array original. Por el contrario, una copia profunda de una matriz copia los elementos y todo lo que los elementos hacen referencia directa o indirectamente. msdn.microsoft.com/en-us/library/system.array.clone.aspx
Mike
@PatrickDesjardins. No está muy claro para mí. Si ambos son copia superficial Entonces, ¿qué es copia profunda? ¿Por qué CopyTo () es copia superficial?
KumarHarsh
1
En .Net 3.5, el ToArray()método de Linq proporciona una forma mucho más simple (y mecanografiada ) de clonar un arreglo superficial de todos modos. Dado que Array es IENumerable<T>, funciona en él.
Nyerguds
27

Otra diferencia no mencionada hasta ahora es que

  • con Clone()la matriz de destino no es necesario que exista todavía, ya que se crea una nueva desde cero.
  • con CopyTo()no sólo la necesidad matriz de destino ya de existir, tiene que ser lo suficientemente grande para contener todos los elementos de la matriz de origen desde el índice especificado como destino.
Michael Burr
fuente
22

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.

Caracteristicas de System.Array.Clone:

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

Caracteristicas de System.Array.CopyTo:

  • Es más rápido queClone cuando se copia en una matriz del mismo tipo;
  • Llama a Array.Copyheredar sus capacidades , siendo las más útiles:
    • Puede encuadrar elementos de tipo de valor en elementos de tipo de referencia, por ejemplo, copiando una int[]matriz en un object[];
    • Puede desempaquetar elementos de tipo de referencia en elementos de tipo de valor, por ejemplo, copiando una object[]matriz de encuadrados inten un int[];
    • Puede realizar conversiones de ampliación en tipos de valor, por ejemplo, copiando un int[]en un long[].
    • Puede abatir elementos, por ejemplo, copiando una Stream[]matriz en un MemoryStream[](si cualquier elemento en la matriz fuente no es convertible a MemoryStreamuna excepción, se lanza).
  • 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 ICloneabley ICollection, por lo que si está tratando con variables de tipos de matriz, no debe usar Cloneo CopyToy en su lugar use Array.Copyo Array.ConstrainedCopy. La copia restringida asegura que si la operación de copia no se puede completar correctamente, el estado de la matriz de destino no está dañado.

João Angelo
fuente
Esta es una información sólida. Entonces, ¿por qué no escribimos una versión genérica más rápida de Clone? Algo como: Ej: public static T [] ExtFastClone <T> (este T [] arr) {if (null == arr) {return null; } T [] arr2 = nuevo T [arr.Length]; arr.CopyTo (arr2, 0); return arr2; } O puede hacer una versión de conversión (para permitir int -> long) como: public static TOut [] ExtFastClone <TIn, TOut> (this TIn [] arr)
kevinarpe
Para la clonación superficial en .Net 3.5 o superior, puede usar el .ToArray()método de Linq . Hace una copia de todos modos y se puede ejecutar en cualquiera IEnumerable<>, incluidas las matrices. Y a diferencia .Clone(), está escrito, por lo que no se necesita casting.
Nyerguds
21

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

Sin embargo, le CopyTopermite copiar una matriz a un índice específico en la matriz de destino, lo que le da una flexibilidad significativamente mayor.

FlySwat
fuente
8
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

GenZiy
fuente
1
Supongo que una copia poco clara significa que solo se copian las referencias, no el valor. Así que si va a cambiar el valor de myarray [0] de "uno" a 0, entonces debe no el valor del MyArray1 [0] y myarray [1] también ser 0.
Adarsh Kumar
1
Lo siento, pero tu conjetura es incorrecta. La copia superficial no es una copia de las referencias: "El método MemberwiseClone crea una copia superficial creando un nuevo objeto y luego copiando los campos no estáticos del objeto actual en el nuevo objeto". ver msdn.microsoft.com/en-us/library/…
GenZiy
1
La copia superficial o profunda es irrelevante si los tipos que coloca en su matriz son primitivos / inmutables . Las cadenas y los enteros siempre producen una nueva copia cuando se colocan en otra cosa. Para probar la copia profunda, coloque un objeto complejo (como una matriz) en uno de los puntos.
Nyerguds
2

Tanto CopyTo () como Clone () hacen una copia superficial. El método Clone () hace un clon 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 la matriz de destino especificado. Tenga en cuenta que esto agrega elementos a una matriz ya existente.

El siguiente código contradice 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 explicarte un poco. Si los elementos de la matriz son de tipos de referencia, entonces la copia (tanto para Clone () como para CopyTo ()) se realizará hasta el primer nivel (superior). Pero el nivel inferior no se copia. Si también necesitamos una copia de nivel inferior, tenemos que hacerlo explícitamente. Es por eso que después de la clonación o copia de elementos de tipo de referencia, cada elemento de la matriz clonada o copiada 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 Copiado o Clonado no tendría efecto en el elemento correspondiente de la matriz original.

Creo que mi explicación es exhaustiva pero no encontré otra forma de hacerla comprensible.

Prasad
fuente
1

Array.Clone()realizaría una copia técnicamente profunda, cuando pasa la matriz into cadena a un método como referencia.

Por ejemplo

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

Incluso si los métodos clasifican la matriz de números, pero no afectará la referencia real pasada a los métodos de clasificación, es decir, la matriz de números estará en el mismo formato inicial sin clasificar en la línea no 1.

Nota: El clon debe realizarse en los métodos de clasificación.

Umasankar Siva
fuente
0

El Clone()método no hace referencia a la instancia de destino, solo le da una copia. el CopyTo()método 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.

Mohammad Ahmed
fuente
0

Las respuestas me confunden. Cuando dices copia superficial, esto significa que todavía apuntan a la misma dirección. Lo que significa que cambiar cualquiera de ellos 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?

Desconocido
fuente
No. si cambiamos el valor de la matriz b, afectará solo a esa matriz b. no la matriz A.
Gomathipriya
Los números enteros, cadenas, fechas, etc. nunca se copian por referencia, personas . Poco profundo significa "solo un nivel de profundidad". Significa que los tipos de referencia (matrices u otros objetos complejos) seguirán apuntando a los mismos objetos. Tipos no primitivos / inmutables; esos están diseñados para no usarse nunca como referencias.
Nyerguds
Las copias superficiales se aplican solo a objetos complejos, como estructuras, cadenas, listas, etc. Una matriz Int o doble siempre tendrá una copia profunda.
Zuabros
0

Ambos son copias superficiales. El método CopyTo no es una copia profunda. Verifique 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 */
Nikhil Redij
fuente
0

Array.Clone no requiere que haya una matriz de destino / destino disponible al llamar a la función, mientras que Array.CopyTo requiere una matriz de destino y un índice.

Aikansh Mann
fuente
-1

Clone() se usa para copiar solo la estructura de datos / matriz, no copia los datos reales.

CopyTo() copia la estructura y los datos reales.

abatishchev
fuente
-2

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

En String: si cambia el String, las otras matrices que hemos copiado (por CopyTo o Clone) que apuntan a la misma cadena no cambiarán, pero la matriz de String original apuntará a una nueva String, 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
}
inbaly
fuente
1
Esto no está relacionado a CopyTovs Clone. Es solo semántica de referencia frente a semántica de valor. int es un tipo de valor, por lo que obtiene una nueva copia cada vez. StringBuilder tiene semántica de referencia, por lo que está actuando sobre la misma copia.
nawfal
@nawfal - Lo sé, por eso escribí 'tenga en cuenta' ... hay una diferencia de comportamiento entre String, StringBuilder e int, en copyto y clone, y puede ser confuso para alguien que no lo sepa.
inbaly