2009-07-31 15 views
13

Tengo una matriz tipada MyType[] types; y quiero hacer una copia independiente de esta matriz. Intenté estoC# copiar matriz por valor

MyType[] types2 = new MyType[types.Length] ; 

types2 = types ; 

pero esto crea una referencia a la primera. Luego intenté

Array.Copy(types , types2 , types.Length) ; 

pero tengo el mismo problema: cambiar un valor en la primera matriz también cambia el valor de la copia.

¿Cómo puedo hacer una copia completamente independiente o profunda de un Array, IList o IEnumerable?

Respuesta

9

Implemente un método de clonación en MyType, utilizando el método protegido MemberwiseClone (realiza una copia superficial) o usando una técnica de clonación profunda. Puede hacer que implemente un ICloneable y luego escribir varios métodos de extensiones que clonarán la colección correspondiente.

interface ICloneable<T> 
{ 
    T Clone(); 
} 

public static class Extensions 
{ 
    public static T[] Clone<T>(this T[] array) where T : ICloneable<T> 
    { 
     var newArray = new T[array.Length]; 
     for (var i = 0; i < array.Length; i++) 
      newArray[i] = array[i].Clone(); 
     return newArray; 
    } 
    public static IEnumerable<T> Clone<T>(this IEnumerable<T> items) where T : ICloneable<T> 
    { 
     foreach (var item in items) 
      yield return item.Clone(); 
    } 
} 

Debe hacer esto porque mientras se crea una nueva matriz cuando se utiliza Array.Copy copia los referencias, no los objetos referenciados. Cada tipo es responsable de copiarse a sí mismo.

+1

Microsoft dice: [se recomienda que ICloneable no se aplicará en API públicas] (http://msdn.microsoft.com/en-us/library/system.icloneable (v = v .110) .aspx) porque no especifica la semántica de copia profunda vs. superficial. Mejor crear una propia interfaz IDeepCopyable. – Wilbert

11

Según la primera publicación, todo lo que necesita es esto para "una copia independiente de la matriz". Los cambios en la matriz shallowCopy no aparecerán en la matriz types (es decir, asignación de elemento, que en realidad es lo que mostró anteriormente a pesar de decir "copia profunda"). Si esto se adapta a sus necesidades, tendrá el mejor rendimiento.

MyType[] shallowCopy = (MyType[])types.Clone(); 

También menciona una "copia en profundidad", que sería diferente para tipos mutables que no son agregados de tipo valor recursivas de primitivas. Si el MyType implementa ICloneable, esto funciona muy bien para una copia profunda:

MyType[] deepCopy = (MyType[])Array.ConvertAll(element => (MyType)element.Clone()); 
6

Si el tipo es serializable puede utilizar técnicas de serialización para obtener una copia de la matriz (incluyendo copias en profundidad de los artículos):

private static object GetCopy(object input) 
{ 
    using (MemoryStream stream = new MemoryStream()) 
    { 
     BinaryFormatter formatter = new BinaryFormatter(); 
     formatter.Serialize(stream, input); 
     stream.Position = 0; 
     return formatter.Deserialize(stream); 
    } 
} 

para usarlo:

MyType[] items = new MyType[2]; 
// populate the items in the array 

MyType[] copies = (MyType[])GetCopy(items); 
+0

mi tipo no es serializable = ( – JOBG

+0

Esto es genial !!! –

3

que quería hacer lo mismo: hacer una copia de una matriz por valor de cosas como la clasificación de manera que pude l ater reinicializar otra matriz temporal con la matriz fuente original. Después de investigar esto, descubrí que esto no se puede hacer de manera tan simple. Entonces, hice una solución. Voy a utilizar mi propio código de abajo:

string[] planetNames = new string[] { "earth", "venus", "mars" }; 

string[] tempNames = new string[planetNames.Length]; 

for (int i = 0; i < planetNames.Length; i++) 
{ 
    tempNames[i] = planetNames[i]; 
} 

planetNames es mi matriz de origen. tempNames es la matriz que clasificaré más adelante independientemente de planetNames. He probado esto y este código no ordena planetNames cuando ordeno tempNames que es lo que estaba intentando lograr.

0

que he encontrado, si lo que desea es un simple matriz de caracteres de copia que puede engañar a C# para que haga una copia de valor utilizando el carbón:

char[] newchararray = new char[desiredchararray.Length]; 

for (int k = 0; k < desiredchararray.Length; k++) 
{ 

    char thecharacter = newchararray[k]; 
    newchararray[k] = thecharacter; 
    oldchararray[k] = oldchararray[k] + 1; 

} 

parece funcionar para mí, pero si alguien no está de acuerdo por favor, vamos saber :)

+2

char es un tipo de valor. Esto funcionará diferente para los tipos de referencia. – Odrade

7

para los impacientes:

newarray = new List<T>(oldarray).ToArray(); 
1

Si desea crear una copia de sólo una serie de referencias a objetos en matriz de edad (o si tiene gran variedad de objetos de tipo de valor) , Solución más simple es

var newArray = oldArray.ToArray() 

Si desea copia en profundidad que debe tener un método que permite realizar copias solo objeto de su tipo (por ejemplo, public MyType Copy(MyType obj)). A continuación, la solución se verá como

var newArray = oldArray.Select(x => Copy(x)).ToArray() 
+0

Para aclarar, 'Copiar (x)' es una implementación personalizada, ¿verdad? – Thor

+1

Sí, no hay un método para realizar una copia profunda del objeto de ningún tipo. Hay [MemberwiseClone] (https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone (v = vs.110) .aspx) método en cualquier objeto, pero está protegido y crea solo una copia superficial (copia del objeto en sí, pero no crea nuevas copias de los campos del tipo de referencia), no una copia en profundidad. – renadeen

Cuestiones relacionadas