Ich habe ein generisches Wörterbuchwörterbuch, das ich im Wesentlichen machen möchte.
Okay, das .NET 2.0 antwortet:
Wenn Sie die Werte nicht klonen müssen, können Sie die Konstruktorüberladung für Dictionary verwenden, wodurch ein vorhandenes IDictionary verwendet wird. (Sie können den Vergleicher auch als Vergleicher des vorhandenen Wörterbuchs angeben.)
Wenn Sie do die Werte klonen müssen, können Sie Folgendes verwenden:
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;
}
Dies setzt natürlich voraus, dass TValue.Clone()
ein entsprechend tiefer Klon ist.
(Anmerkung: Obwohl die Klonversion möglicherweise nützlich ist, ist der Konstruktor, den ich in dem anderen Beitrag erwähnte, für eine einfache flache Kopie eine bessere Option.)
Wie tief soll die Kopie sein und welche Version von .NET verwenden Sie? Ich vermute, dass ein LINQ-Aufruf von ToDictionary, der sowohl die Schlüssel- als auch die Elementauswahl angibt, der einfachste Weg ist, wenn Sie .NET 3.5 verwenden.
Wenn Sie beispielsweise nichts dagegen haben, dass der Wert ein flacher Klon ist:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => entry.Value);
Wenn Sie bereits T zur Implementierung von ICloneable eingeschränkt haben:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => (T) entry.Value.Clone());
(Die sind nicht getestet, sollten aber funktionieren.)
Dictionary<string, int> dictionary = new Dictionary<string, int>();
Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
Für .NET 2.0 können Sie eine Klasse implementieren, die von Dictionary
erbt und ICloneable
implementiert.
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;
}
}
Sie können das Wörterbuch dann einfach klonen, indem Sie die Clone
-Methode aufrufen. Natürlich erfordert diese Implementierung, dass der Werttyp des Wörterbuchs ICloneable
implementiert, ansonsten ist eine generische Implementierung jedoch nicht praktisch.
Sie können immer die Serialisierung verwenden. Sie könnten das Objekt serialisieren und dann deserialisieren. Dadurch erhalten Sie eine tiefe Kopie des Wörterbuchs und aller darin enthaltenen Elemente. Jetzt können Sie eine tiefe Kopie eines Objekts erstellen, das als [Serializable] markiert ist, ohne einen speziellen Code zu schreiben.
Hier sind zwei Methoden, die die binäre Serialisierung verwenden. Wenn Sie diese Methoden verwenden, rufen Sie einfach auf
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;
}
Der beste Weg für mich ist dieser:
Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);
Die binäre Serialisierungsmethode funktioniert gut, aber in meinen Tests zeigte sich, dass sie 10x langsamer ist als eine nicht-Serialisierungsimplementierung des Klons. Getestet auf Dictionary<string , List<double>>
Das funktioniert gut für mich
// assuming this fills the List
List<Dictionary<string, string>> obj = this.getData();
List<Dictionary<string, string>> objCopy = new List<Dictionary<string, string>>(obj);
Ich habe auf alte Post geantwortet, aber ich fand es nützlich, es wie folgt zu verpacken:
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;
}
}
Versuchen Sie dies, wenn Schlüssel/Werte ICloneable sind:
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;
}