¿Cuál es la mejor forma de clonar / copiar en profundidad un diccionario genérico .NET ?

Tengo un Diccionario de diccionario genérico que me gustaría esencialmente hacer un Clon () de … cualquier sugerencia.

De acuerdo, el .NET 2.0 responde:

Si no necesita clonar los valores, puede usar la sobrecarga del constructor para Dictionary que toma un IDictionary existente. (También puede especificar el comparador como el comparador del diccionario existente).

Si necesita clonar los valores, puede usar algo como esto:

public static Dictionary CloneDictionaryCloningValues (Dictionary original) where TValue : ICloneable { Dictionary ret = new Dictionary(original.Count, original.Comparer); foreach (KeyValuePair entry in original) { ret.Add(entry.Key, (TValue) entry.Value.Clone()); } return ret; } 

Eso depende de que TValue.Clone() sea ​​un clon adecuadamente profundo, por supuesto.

(Nota: aunque la versión de clonación es potencialmente útil, para una simple copia poco profunda, el constructor que menciono en la otra publicación es una mejor opción).

¿Qué tan profundo quieres que sea la copia y qué versión de .NET estás usando? Sospecho que una llamada LINQ a ToDictionary, especificando tanto la tecla como el selector de elementos, será la forma más fácil de hacerlo si está usando .NET 3.5.

Por ejemplo, si no te importa que el valor sea un clon superficial:

 var newDictionary = oldDictionary.ToDictionary(entry => entry.Key, entry => entry.Value); 

Si ya ha restringido T para implementar ICloneable:

 var newDictionary = oldDictionary.ToDictionary(entry => entry.Key, entry => (T) entry.Value.Clone()); 

(Esos no han sido probados, pero deberían funcionar).

 Dictionary dictionary = new Dictionary(); Dictionary copy = new Dictionary(dictionary); 

Para .NET 2.0, podría implementar una clase que herede de Dictionary e implemente ICloneable .

 public class CloneableDictionary : Dictionary where TValue : ICloneable { public IDictionary Clone() { CloneableDictionary clone = new CloneableDictionary(); foreach (KeyValuePair pair in this) { clone.Add(pair.Key, (TValue)pair.Value.Clone()); } return clone; } } 

A continuación, puede clonar el diccionario simplemente llamando al método Clone . Por supuesto, esta implementación requiere que el tipo de valor del diccionario implemente ICloneable , pero de lo contrario una implementación genérica no es práctica en absoluto.

Siempre puedes usar la serialización. Puedes serializar el objeto y luego deserializarlo. Eso le dará una copia profunda del diccionario y todos los elementos dentro de él. Ahora puede crear una copia profunda de cualquier objeto que esté marcado como [Serializable] sin escribir ningún código especial.

Aquí hay dos métodos que utilizarán la serialización binaria. Si usa estos métodos, simplemente llame

 object deepcopy = FromBinary(ToBinary(yourDictionary)); public Byte[] ToBinary() { MemoryStream ms = null; Byte[] byteArray = null; try { BinaryFormatter serializer = new BinaryFormatter(); ms = new MemoryStream(); serializer.Serialize(ms, this); byteArray = ms.ToArray(); } catch (Exception unexpected) { Trace.Fail(unexpected.Message); throw; } finally { if (ms != null) ms.Close(); } return byteArray; } public object FromBinary(Byte[] buffer) { MemoryStream ms = null; object deserializedObject = null; try { BinaryFormatter serializer = new BinaryFormatter(); ms = new MemoryStream(); ms.Write(buffer, 0, buffer.Length); ms.Position = 0; deserializedObject = serializer.Deserialize(ms); } finally { if (ms != null) ms.Close(); } return deserializedObject; } 

El método de serialización binaria funciona bien, pero en mis pruebas demostró ser 10 veces más lento que una implementación de clonación sin serialización. Probado en Dictionary>

La mejor manera para mí es esta:

 Dictionary copy= new Dictionary(yourListOrDictionary); 

Esto funciona bien para mi

  // assuming this fills the List List> obj = this.getData(); List> objCopy = new List>(obj); 

Intenta esto si key / values ​​son ICloneable:

  public static Dictionary CloneDictionary(Dictionary dict) where K : ICloneable where V : ICloneable { Dictionary newDict = null; if (dict != null) { // If the key and value are value types, just use copy constructor. if (((typeof(K).IsValueType || typeof(K) == typeof(string)) && (typeof(V).IsValueType) || typeof(V) == typeof(string))) { newDict = new Dictionary(dict); } else // prepare to clone key or value or both { newDict = new Dictionary(); foreach (KeyValuePair kvp in dict) { K key; if (typeof(K).IsValueType || typeof(K) == typeof(string)) { key = kvp.Key; } else { key = (K)kvp.Key.Clone(); } V value; if (typeof(V).IsValueType || typeof(V) == typeof(string)) { value = kvp.Value; } else { value = (V)kvp.Value.Clone(); } newDict[key] = value; } } } return newDict; } 

Sin embargo, en respuesta a la publicación anterior, me pareció útil incluirlo de la siguiente manera:

 using System; using System.Collections.Generic; public class DeepCopy { public static Dictionary CloneKeys(Dictionary dict) where T1 : ICloneable { if (dict == null) return null; Dictionary ret = new Dictionary(); foreach (var e in dict) ret[(T1)e.Key.Clone()] = e.Value; return ret; } public static Dictionary CloneValues(Dictionary dict) where T2 : ICloneable { if (dict == null) return null; Dictionary ret = new Dictionary(); foreach (var e in dict) ret[e.Key] = (T2)(e.Value.Clone()); return ret; } public static Dictionary Clone(Dictionary dict) where T1 : ICloneable where T2 : ICloneable { if (dict == null) return null; Dictionary ret = new Dictionary(); foreach (var e in dict) ret[(T1)e.Key.Clone()] = (T2)(e.Value.Clone()); return ret; } }