Risposte:
Bene, .NET 2.0 risponde:
Se non è necessario clonare i valori, è possibile utilizzare il overload del costruttore su Dizionario che accetta un IDictionary esistente. (Puoi anche specificare il comparatore come comparatore del dizionario esistente.)
Se non c'è bisogno di clonare i valori, è possibile utilizzare qualcosa di simile a questo:
public static Dictionary<TKey, TValue> CloneDictionaryCloningValues<TKey, TValue>
(Dictionary<TKey, TValue> original) where TValue : ICloneable
{
Dictionary<TKey, TValue> ret = new Dictionary<TKey, TValue>(original.Count,
original.Comparer);
foreach (KeyValuePair<TKey, TValue> entry in original)
{
ret.Add(entry.Key, (TValue) entry.Value.Clone());
}
return ret;
}
Ciò dipende TValue.Clone()
ovviamente dall'essere un clone adeguatamente profondo.
Clone()
metodo se è profondo o superficiale. Ho aggiunto una nota in tal senso.
ConcurrentDictionary
.
(Nota: sebbene la versione della clonazione sia potenzialmente utile, per una semplice copia superficiale il costruttore che cito nell'altro post è un'opzione migliore.)
Quanto in profondità vuoi che sia la copia e quale versione di .NET stai usando? Sospetto che una chiamata LINQ a ToDictionary, specificando sia la chiave che il selettore di elementi, sarà il modo più semplice di procedere se si utilizza .NET 3.5.
Ad esempio, se non ti dispiace che il valore sia un clone superficiale:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => entry.Value);
Se hai già vincolato T per implementare ICloneable:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => (T) entry.Value.Clone());
(Quelli non sono testati, ma dovrebbero funzionare.)
Dictionary<string, int> dictionary = new Dictionary<string, int>();
Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
Per .NET 2.0 è possibile implementare una classe che eredita Dictionary
e implementa ICloneable
.
public class CloneableDictionary<TKey, TValue> : Dictionary<TKey, TValue> where TValue : ICloneable
{
public IDictionary<TKey, TValue> Clone()
{
CloneableDictionary<TKey, TValue> clone = new CloneableDictionary<TKey, TValue>();
foreach (KeyValuePair<TKey, TValue> pair in this)
{
clone.Add(pair.Key, (TValue)pair.Value.Clone());
}
return clone;
}
}
È quindi possibile clonare il dizionario semplicemente chiamando il Clone
metodo. Naturalmente questa implementazione richiede che il tipo di valore del dizionario sia implementato ICloneable
, ma per il resto un'implementazione generica non è affatto pratica.
Questo funziona bene per me
// assuming this fills the List
List<Dictionary<string, string>> obj = this.getData();
List<Dictionary<string, string>> objCopy = new List<Dictionary<string, string>>(obj);
Come descritto da Tomer Wolberg nei commenti, questo non funziona se il tipo di valore è una classe mutabile.
Puoi sempre usare la serializzazione. È possibile serializzare l'oggetto quindi deserializzarlo. Questo ti darà una copia approfondita del Dizionario e di tutti gli elementi al suo interno. Ora puoi creare una copia profonda di qualsiasi oggetto contrassegnato come [serializzabile] senza scrivere alcun codice speciale.
Ecco due metodi che useranno la serializzazione binaria. Se usi questi metodi, chiami semplicemente
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;
}
Il modo migliore per me è questo:
Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);
Il metodo di serializzazione binaria funziona bene, ma nei miei test ha dimostrato di essere 10 volte più lento di un'implementazione non seriale di clone. Testato suDictionary<string , List<double>>
ToBinary()
il Serialize()
metodo viene chiamato con this
al posto di yourDictionary
. Quindi nel FromBinary()
byte [] viene prima copiato manualmente in MemStream ma può essere semplicemente fornito al suo costruttore.
Questo è ciò che mi ha aiutato, quando stavo cercando di copiare in profondità un dizionario <stringa, stringa>
Dictionary<string, string> dict2 = new Dictionary<string, string>(dict);
In bocca al lupo
Prova questo se chiave / valori sono ICloneable:
public static Dictionary<K,V> CloneDictionary<K,V>(Dictionary<K,V> dict) where K : ICloneable where V : ICloneable
{
Dictionary<K, V> 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<K, V>(dict);
}
else // prepare to clone key or value or both
{
newDict = new Dictionary<K, V>();
foreach (KeyValuePair<K, V> 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;
}
Rispondendo ai vecchi post però ho trovato utile avvolgerlo come segue:
using System;
using System.Collections.Generic;
public class DeepCopy
{
public static Dictionary<T1, T2> CloneKeys<T1, T2>(Dictionary<T1, T2> dict)
where T1 : ICloneable
{
if (dict == null)
return null;
Dictionary<T1, T2> ret = new Dictionary<T1, T2>();
foreach (var e in dict)
ret[(T1)e.Key.Clone()] = e.Value;
return ret;
}
public static Dictionary<T1, T2> CloneValues<T1, T2>(Dictionary<T1, T2> dict)
where T2 : ICloneable
{
if (dict == null)
return null;
Dictionary<T1, T2> ret = new Dictionary<T1, T2>();
foreach (var e in dict)
ret[e.Key] = (T2)(e.Value.Clone());
return ret;
}
public static Dictionary<T1, T2> Clone<T1, T2>(Dictionary<T1, T2> dict)
where T1 : ICloneable
where T2 : ICloneable
{
if (dict == null)
return null;
Dictionary<T1, T2> ret = new Dictionary<T1, T2>();
foreach (var e in dict)
ret[(T1)e.Key.Clone()] = (T2)(e.Value.Clone());
return ret;
}
}
entry.Value
valore potrebbe essere ancora un'altra [sotto] raccolta.