Ответы:
Хорошо. .NET 2.0 отвечает:
Если вам не нужно клонировать значения, вы можете использовать перегрузку конструктора для словаря, который принимает существующий IDictionary. (Вы также можете указать компаратор как компаратор существующего словаря.)
Если вам действительно нужно клонировать значения, вы можете использовать что - то вроде этого:
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()
Конечно, это зависит и от того, что вы достаточно глубокий клон.
Clone()
метода, глубокого или мелкого. Я добавил примечание на этот счет.
ConcurrentDictionary
.
(Примечание: хотя версия для клонирования потенциально полезна, для простой поверхностной копии лучше использовать конструктор, о котором я упоминал в другом посте.)
Насколько глубокой должна быть копия и какую версию .NET вы используете? Я подозреваю, что LINQ-вызов ToDictionary, указывающий и ключ, и селектор элемента, будет самым простым способом, если вы используете .NET 3.5.
Например, если вы не возражаете против значения, являющегося мелким клоном:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => entry.Value);
Если вы уже ограничивали T для реализации ICloneable:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => (T) entry.Value.Clone());
(Они не проверены, но должны работать.)
Dictionary<string, int> dictionary = new Dictionary<string, int>();
Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
Для .NET 2.0 вы можете реализовать класс, который наследует Dictionary
и реализует 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;
}
}
Затем вы можете клонировать словарь, просто вызвав Clone
метод. Конечно, эта реализация требует, чтобы тип значения словаря реализовывал ICloneable
, но в общем случае универсальная реализация вообще не практична.
У меня это нормально работает
// assuming this fills the List
List<Dictionary<string, string>> obj = this.getData();
List<Dictionary<string, string>> objCopy = new List<Dictionary<string, string>>(obj);
Как описывает Томер Вольберг в комментариях, это не работает, если тип значения является изменяемым классом.
Вы всегда можете использовать сериализацию. Вы можете сериализовать объект, а затем десериализовать его. Это даст вам глубокую копию словаря и всех предметов внутри него. Теперь вы можете создать полную копию любого объекта, помеченного как [Serializable], без написания какого-либо специального кода.
Вот два метода, которые будут использовать двоичную сериализацию. Если вы используете эти методы, вы просто вызываете
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;
}
Лучший способ для меня это:
Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);
Метод двоичной сериализации работает нормально, но в моих тестах он показал, что он в 10 раз медленнее, чем реализация клонов без сериализации. Протестировано наDictionary<string , List<double>>
ToBinary()
в Serialize()
методе вызывается this
вместо yourDictionary
. Затем в FromBinary()
byte [] сначала копируется вручную в MemStream, но он может быть просто передан в свой конструктор.
Вот что мне помогло, когда я пытался глубоко скопировать словарь <строка, строка>
Dictionary<string, string> dict2 = new Dictionary<string, string>(dict);
Удачи
Попробуйте это, если ключ / значения 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;
}
Отвечая на старый пост, я счел полезным обернуть его следующим образом:
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
Значение может быть еще один [суб] коллекция.