Odpowiedzi:
W porządku .NET 2.0 odpowiada:
Jeśli nie musisz klonować wartości, możesz użyć przeciążenia konstruktora do Dictionary, który pobiera istniejące IDictionary. (Możesz również porównać moduł porównujący jako istniejący moduł porównujący słownika.)
Jeśli nie trzeba sklonować wartości, można użyć coś takiego:
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()
Oczywiście zależy to również od bycia odpowiednio głębokim klonem.
Clone()
metody, czy jest głęboka czy płytka. Dodałem notatkę do tego efektu.
ConcurrentDictionary
.
(Uwaga: chociaż wersja klonowania jest potencjalnie przydatna, dla zwykłego płytkiego kopiowania konstruktor, o którym wspomniałem w innym poście, jest lepszym rozwiązaniem).
Jak głęboko chcesz mieć kopię i jakiej wersji .NET używasz? Podejrzewam, że wywołanie LINQ do ToDictionary, określające zarówno klucz, jak i selektor elementów, będzie najłatwiejszym sposobem, jeśli używasz .NET 3.5.
Na przykład, jeśli nie przeszkadza ci, że wartość jest płytkim klonem:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => entry.Value);
Jeśli już ograniczyłeś T do implementacji ICloneable:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => (T) entry.Value.Clone());
(Te są nieprzetestowane, ale powinny działać.)
Dictionary<string, int> dictionary = new Dictionary<string, int>();
Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
W przypadku .NET 2.0 można zaimplementować klasę, która dziedziczy Dictionary
i implementuje 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;
}
}
Następnie można sklonować słownik, po prostu wywołując Clone
metodę. Oczywiście ta implementacja wymaga implementacji typu wartości słownika ICloneable
, ale w przeciwnym razie ogólna implementacja nie jest w ogóle praktyczna.
To działa dobrze dla mnie
// assuming this fills the List
List<Dictionary<string, string>> obj = this.getData();
List<Dictionary<string, string>> objCopy = new List<Dictionary<string, string>>(obj);
Jak Tomer Wolberg opisuje w komentarzach, nie działa to, jeśli typem wartości jest zmienna klasa.
Zawsze możesz użyć serializacji. Możesz serializować obiekt, a następnie deserializować go. To da ci głęboką kopię Słownika i wszystkich jego elementów. Teraz możesz utworzyć głęboką kopię dowolnego obiektu oznaczonego jako [Serializable] bez pisania specjalnego kodu.
Oto dwie metody, które wykorzystają Serializacja binarna. Jeśli używasz tych metod, po prostu dzwonisz
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;
}
Najlepszy sposób dla mnie to:
Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);
Metoda szeregowania binarnego działa dobrze, ale w moich testach okazała się 10 razy wolniejsza niż implementacja klonowania bez serializacji. Testowałem toDictionary<string , List<double>>
ToBinary()
tej Serialize()
metodzie jest wywołana this
zamiast yourDictionary
. Następnie w FromBinary()
bajcie [] jest najpierw kopiowany ręcznie do MemStream, ale można go po prostu dostarczyć do jego konstruktora.
To mi pomogło, gdy próbowałem głęboko skopiować słownik <ciąg, ciąg>
Dictionary<string, string> dict2 = new Dictionary<string, string>(dict);
Powodzenia
Spróbuj tego, jeśli klucz / wartości można 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;
}
Odpowiadając na stary post, uznałem jednak, że warto go zawinąć w następujący sposób:
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
Wartość może być jeszcze inny [sub] kolekcja.