Відповіді:
Гаразд, .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()
байт [] спочатку копіюється вручну в 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
Значення може бути ще один [суб] колекція.