¿Cómo hacer una copia profunda de una matriz?

Paso una matriz bidimensional como propiedad de mi control de usuario. Ahí guardo estos valores en otra matriz bidimensional:

int[,] originalValues = this.Metrics; 

Más tarde cambio los valores en this.Metrics . Pero ahora si recupero valores de los valores originales, obtengo los valores modificados de this.Metrics . this.Metrics . ¿Cómo hago una copia profunda y no solo copio las referencias en C #?

Puede clonar una matriz, que hace una copia de ella:

 int[,] originalValues = (int[,])this.Metrics.Clone(); 

No sé de dónde saqué esto, pero esto funciona bien para mí.

 public static class GenericCopier //deep copy a list { public static T DeepCopy(object objectToCopy) { using (MemoryStream memoryStream = new MemoryStream()) { BinaryFormatter binaryFormatter = new BinaryFormatter(); binaryFormatter.Serialize(memoryStream, objectToCopy); memoryStream.Seek(0, SeekOrigin.Begin); return (T)binaryFormatter.Deserialize(memoryStream); } } } 

Si el objeto que está copiando es una matriz, puede usar:

 Array.Copy(sourceArray, destinationArray, sourceArray.Count) 

Esto le dará una copia separada de la matriz original en su matriz de destino.

El quid de su problema está aquí:

Allí almaceno estos valores en otra matriz bidimensional

Esto es realmente inexacto. No estás creando una nueva matriz; está configurando su variable originalValues a la misma matriz . Para una explicación más detallada, ver a continuación.


La confusión expresada en los comentarios a la respuesta de Pieter se debe a cierta incertidumbre en torno al término “copia profunda”.

Cuando se trata de copiar objetos, hay una copia profunda y una copia poco profunda.

La copia profunda implica hacer una copia de todos los datos que pertenecen a un objeto, lo que significa que si el objeto incluye miembros que son complejos (por ejemplo, instancias de tipos de referencia definidos por el usuario), también deben copiarse profundamente ( junto con todos sus miembros, etc.).

La copia superficial implica simplemente copiar todos los campos de un objeto a otro, lo que significa que si el objeto incluye tipos de referencia, solo se deben copiar las referencias (y las referencias copiadas apuntan a los mismos objetos).

En el caso del código que ha publicado:

 int[,] originalValues = this.Metrics; 

… en realidad no hay copia de ningún objeto en absoluto . Todo lo que ha hecho es copiar una sola referencia, asignando el valor de this.Metrics (una referencia) a la variable originalValues (también una referencia, a la misma matriz). Esto es esencialmente lo mismo que una simple asignación de valores, como esta:

 int x = y; // No objects being copied here. 

Ahora, el método Array.Clone hace, de hecho, una copia poco profunda . Pero, como señaló Pieter, en realidad no hay diferencia entre una copia “superficial” o “profunda” de una matriz de enteros , ya que los enteros no son objetos complejos.

Si tuvieras algo como esto:

 StringBuilder[,] builders = GetStringBuilders(); StringBuilder[,] builderCopies = (StringBuilder[,])builders.Clone(); 

…, terminarías con una nueva matriz (una copia, sí), pero una que contiene todos los mismos objetos StringBuilder (por lo que una copia poco profunda). Aquí es donde entra en juego la copia profunda frente a la superficial; si desea una nueva matriz que contenga copias de todos los objetos StringBuilder de los builders , deberá hacer una copia profunda.

Puede hacer una copia profunda de una matriz 1d usando LINQ.

 var array = Enumerable.Range(0, 10).ToArray(); var array2 = array.Select(x => x).ToArray(); array2[0] = 5; Console.WriteLine(array[0]); // 0 Console.WriteLine(array2[0]); // 5 

Con 2d array, esto no funcionará porque la matriz 2d no implementa IEnumerable.

IClonable es genial, pero a menos que IClonable tipo IClonable en su tipo clonado de nivel superior, terminará con referencias, AFAIK.

Basado en eso, a menos que quieras caminar el objeto y clonar cada objeto dentro, este parece ser el enfoque más simple.

Es simple y garantiza una ruptura limpia de las referencias de objetos profundos en el original:

 using Newtonsoft.Json; private T DeepCopy(object input) where T : class { var copy = JsonConvert.SerializeObject((T)input); // serialise to string json object var output = JsonConvert.DeserializeObject(copy); // deserialise back to poco return output; } 

Uso:

 var x = DeepCopy<{ComplexType}>(itemToBeCloned); 

Donde ComplexType es algo que quiere un descanso de las referencias.

Toma cualquier Tipo, lo corrige y luego lo destripa a una nueva copia.

Ejemplo de mejor uso: si seleccionó un tipo complejo como resultado de una consulta lambda y desea modificar el resultado sin afectar el original.

Necesitas crear una nueva matriz. Luego debe copiar manualmente el valor de cada elemento en la nueva matriz. Lo que está haciendo en el ejemplo dado es crear dos variables de matriz que hacen referencia a la misma matriz.

El problema con el método de clonación es que es una copia superficial. En este sentido, porque estás usando int , no importa. Sin embargo, si tuviera una matriz de clases, la definición de la interfaz ICLonable deja ambigua la profundidad del clon.

Imagine si tuviera una clase que tiene propiedades que son otras clases que tienen propiedades que son otras clases. La interfaz clonable no indica si también clonará los sub miembros o no. Además, muchas personas tienen puntos de vista diferentes sobre cuál es el comportamiento esperado.

Por lo tanto, esta es la razón por la cual a menudo se recomienda definir dos interfaces, IShallowCopy e IDeepCopy .

Si desea copiar profundamente una matriz de tipos de referencia, puede hacer esta metodología:

Implemente la IClonable idónea para su clase y realice una copia en profundidad de todos los campos de valor typescript dentro de otro objeto construido.

 class A: ICloneable { int field1; public object Clone() { A a= new A(); //copy your fields here a.field1 = this.field1; ... } } 

Entonces puedes hacer la copia real usando

 A[] array1 = new A[]{....}; A[] array2 = array1.Select(a => a.Clone()).ToList();