Antworten:
Okay, das .NET 2.0 antwortet:
Wenn Sie die Werte nicht klonen müssen, können Sie die Konstruktorüberladung für Dictionary verwenden, die ein vorhandenes IDictionary verwendet. (Sie können den Komparator auch als Komparator des vorhandenen Wörterbuchs angeben.)
Wenn Sie Sie die Werte müssen klonen, können Sie so etwas wie folgt 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;
}
Das hängt TValue.Clone()
natürlich auch davon ab, ein angemessen tiefer Klon zu sein.
Clone()
Methode, ob er tief oder flach ist. Ich habe eine Notiz zu diesem Effekt hinzugefügt.
ConcurrentDictionary
.
(Hinweis: Obwohl die Klonversion möglicherweise nützlich ist, ist für eine einfache flache Kopie der Konstruktor, den ich im anderen Beitrag erwähne, eine bessere Option.)
Wie tief soll die Kopie sein und welche Version von .NET verwenden Sie? Ich vermute, dass ein LINQ-Aufruf von ToDictionary, bei dem sowohl die Schlüssel- als auch die Elementauswahl angegeben werden, der einfachste Weg ist, wenn Sie .NET 3.5 verwenden.
Wenn es Ihnen beispielsweise nichts ausmacht, dass der Wert ein flacher Klon ist:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => entry.Value);
Wenn Sie T bereits auf die Implementierung von ICloneable beschränkt haben:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => (T) entry.Value.Clone());
(Diese sind ungetestet, 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
und implementiert 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;
}
}
Sie können das Wörterbuch dann einfach durch Aufrufen der Clone
Methode klonen . Natürlich erfordert diese Implementierung, dass der Werttyp des Wörterbuchs implementiert wird ICloneable
, aber ansonsten ist eine generische Implementierung überhaupt nicht praktikabel.
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);
Wie Tomer Wolberg in den Kommentaren beschreibt, funktioniert dies nicht, wenn der Werttyp eine veränderbare Klasse ist.
Sie können jederzeit die Serialisierung verwenden. Sie können das Objekt serialisieren und dann deserialisieren. Dadurch erhalten Sie eine ausführliche Kopie des Wörterbuchs und aller darin enthaltenen Elemente. Jetzt können Sie eine tiefe Kopie jedes Objekts erstellen, das als [serialisierbar] 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 folgender:
Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);
Die binäre Serialisierungsmethode funktioniert einwandfrei, aber in meinen Tests hat sie sich als 10-mal langsamer erwiesen als eine Nicht-Serialisierungsimplementierung des Klons. Getestet amDictionary<string , List<double>>
ToBinary()
der Serialize()
Methode wird mit this
statt aufgerufen yourDictionary
. Dann wird FromBinary()
das Byte [] zuerst manuell in den MemStream kopiert, kann aber einfach an seinen Konstruktor übergeben werden.
Das hat mir geholfen, als ich versucht habe, ein Wörterbuch <string, string> tief zu kopieren
Dictionary<string, string> dict2 = new Dictionary<string, string>(dict);
Viel Glück
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;
}
Als ich auf einen alten Beitrag antwortete, fand ich es nützlich, ihn 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;
}
}
entry.Value
Wert könnte eine weitere [Unter-] Sammlung sein.