Réponses:
D'accord, le .NET 2.0 répond:
Si vous n'avez pas besoin de cloner les valeurs, vous pouvez utiliser la surcharge du constructeur dans Dictionary qui prend un IDictionary existant. (Vous pouvez également spécifier le comparateur comme comparateur du dictionnaire existant.)
Si vous ne devez cloner les valeurs, vous pouvez utiliser quelque chose comme ceci:
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;
}
TValue.Clone()
Bien entendu, cela repose également sur un clone suffisamment profond.
Clone()
méthode si elle est profonde ou peu profonde. J'ai ajouté une note à cet effet.
ConcurrentDictionary
.
(Remarque: bien que la version de clonage soit potentiellement utile, pour une simple copie superficielle, le constructeur que je mentionne dans l'autre post est une meilleure option.)
Quelle profondeur souhaitez-vous que la copie soit et quelle version de .NET utilisez-vous? Je soupçonne qu'un appel LINQ à ToDictionary, spécifiant à la fois la clé et le sélecteur d'élément, sera le moyen le plus simple si vous utilisez .NET 3.5.
Par exemple, si cela ne vous dérange pas que la valeur soit un clone peu profond:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => entry.Value);
Si vous avez déjà contraint T à implémenter ICloneable:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => (T) entry.Value.Clone());
(Ceux-ci ne sont pas testés, mais devraient fonctionner.)
Dictionary<string, int> dictionary = new Dictionary<string, int>();
Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
Pour .NET 2.0, vous pouvez implémenter une classe qui hérite de Dictionary
et implémente 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;
}
}
Vous pouvez ensuite cloner le dictionnaire simplement en appelant la Clone
méthode. Bien sûr, cette implémentation nécessite que le type de valeur du dictionnaire implémente ICloneable
, mais sinon une implémentation générique n'est pas du tout pratique.
Cela fonctionne bien pour moi
// assuming this fills the List
List<Dictionary<string, string>> obj = this.getData();
List<Dictionary<string, string>> objCopy = new List<Dictionary<string, string>>(obj);
Comme Tomer Wolberg le décrit dans les commentaires, cela ne fonctionne pas si le type de valeur est une classe mutable.
Vous pouvez toujours utiliser la sérialisation. Vous pouvez sérialiser l'objet puis le désérialiser. Cela vous donnera une copie complète du dictionnaire et de tous les éléments qu'il contient. Vous pouvez maintenant créer une copie complète de tout objet marqué comme [Sérialisable] sans écrire de code spécial.
Voici deux méthodes qui utiliseront la sérialisation binaire. Si vous utilisez ces méthodes, vous appelez simplement
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;
}
La meilleure façon pour moi est la suivante:
Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);
La méthode de sérialisation binaire fonctionne bien, mais dans mes tests, elle s'est révélée 10 fois plus lente qu'une implémentation de non-sérialisation de clone. Testé surDictionary<string , List<double>>
ToBinary()
la Serialize()
méthode est appelée avec this
au lieu de yourDictionary
. Ensuite, dans FromBinary()
l'octet [] est d'abord copié manuellement sur le MemStream mais il peut simplement être fourni à son constructeur.
C'est ce qui m'a aidé, lorsque j'essayais de copier en profondeur un dictionnaire <chaîne, chaîne>
Dictionary<string, string> dict2 = new Dictionary<string, string>(dict);
Bonne chance
Essayez ceci si les clés / valeurs sont IClonables:
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;
}
En répondant à un ancien post, j'ai trouvé utile de le résumer comme suit:
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
valeur peut être encore une autre [sous] collection.