I've got a generic dictionary Dictionary<string, T>
that I would like to essentially make a Clone() of ..any suggestions.
Okay, the .NET 2.0 answers:
If you don't need to clone the values, you can use the constructor overload to Dictionary which takes an existing IDictionary. (You can specify the comparer as the existing dictionary's comparer, too.)
If you do need to clone the values, you can use something like this:
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;
}
That relies on TValue.Clone()
being a suitably deep clone as well, of course.
Clone()
method whether it's deep or shallow. I've added a note to that effect. –
Reeva ConcurrentDictionary
. –
Reeva (Note: although the cloning version is potentially useful, for a simple shallow copy the constructor I mention in the other post is a better option.)
How deep do you want the copy to be, and what version of .NET are you using? I suspect that a LINQ call to ToDictionary, specifying both the key and element selector, will be the easiest way to go if you're using .NET 3.5.
For instance, if you don't mind the value being a shallow clone:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => entry.Value);
If you've already constrained T to implement ICloneable:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => (T) entry.Value.Clone());
(Those are untested, but should work.)
Okay, the .NET 2.0 answers:
If you don't need to clone the values, you can use the constructor overload to Dictionary which takes an existing IDictionary. (You can specify the comparer as the existing dictionary's comparer, too.)
If you do need to clone the values, you can use something like this:
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;
}
That relies on TValue.Clone()
being a suitably deep clone as well, of course.
entry.Value
value might be yet another [sub]collection. –
Mantellone Clone()
method whether it's deep or shallow. I've added a note to that effect. –
Reeva ConcurrentDictionary
. –
Reeva Dictionary<string, int> dictionary = new Dictionary<string, int>();
Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
That's what helped me, when I was trying to deep copy a Dictionary < string, string >
Dictionary<string, string> dict2 = new Dictionary<string, string>(dict);
Good luck
For .NET 2.0 you could implement a class which inherits from Dictionary
and implements 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;
}
}
You can then clone the dictionary simply by calling the Clone
method. Of course this implementation requires that the value type of the dictionary implements ICloneable
, but otherwise a generic implementation isn't practical at all.
This works fine for me
// assuming this fills the List
List<Dictionary<string, string>> obj = this.getData();
List<Dictionary<string, string>> objCopy = new List<Dictionary<string, string>>(obj);
As Tomer Wolberg describes in the comments, this does not work if the value type is a mutable class.
You could always use serialization. You could serialize the object then deserialize it. That will give you a deep copy of the Dictionary and all the items inside of it. Now you can create a deep copy of any object that is marked as [Serializable] without writing any special code.
Here are two methods that will use Binary Serialization. If you use these methods you simply call
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;
}
The best way for me is this:
Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);
new
Dictionary (note the key word "new") and filling it with values of the old object. For an <int,int> it's a perfectly independent copy. –
Voight Binary Serialization method works fine but in my tests it showed to be 10x slower than a non-serialization implementation of clone. Tested it on Dictionary<string , List<double>>
ToBinary()
the Serialize()
method is called with this
instead of yourDictionary
. Then in FromBinary()
the byte[] is first copied manually to the MemStream but it can just be supplied to its constructor. –
Herd Try this if key/values are 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;
}
In the case you have a Dictionary of "object" and object can be anything like (double, int, ... or ComplexClass):
Dictionary<string, object> dictSrc { get; set; }
public class ComplexClass : ICloneable
{
private Point3D ...;
private Vector3D ....;
[...]
public object Clone()
{
ComplexClass clone = new ComplexClass();
clone = (ComplexClass)this.MemberwiseClone();
return clone;
}
}
dictSrc["toto"] = new ComplexClass()
dictSrc["tata"] = 12.3
...
dictDest = dictSrc.ToDictionary(entry => entry.Key,
entry => ((entry.Value is ICloneable) ? (entry.Value as ICloneable).Clone() : entry.Value) );
Here is some real "true deep copying" without knowing type with some recursive walk, good for the beginnig. It is good for nested types and almost any tricky type I think. I did not added nested arrays handling yet, but you can modify it by your choice.
Dictionary<string, Dictionary<string, dynamic>> buildInfoDict =
new Dictionary<string, Dictionary<string, dynamic>>()
{
{"tag",new Dictionary<string,dynamic>(){
{ "attrName", "tag" },
{ "isCss", "False" },
{ "turnedOn","True" },
{ "tag",null }
} },
{"id",new Dictionary<string,dynamic>(){
{ "attrName", "id" },
{ "isCss", "False" },
{ "turnedOn","True" },
{ "id",null }
} },
{"width",new Dictionary<string,dynamic>(){
{ "attrName", "width" },
{ "isCss", "True" },
{ "turnedOn","True" },
{ "width","20%" }
} },
{"height",new Dictionary<string,dynamic>(){
{ "attrName", "height" },
{ "isCss", "True" },
{ "turnedOn","True" },
{ "height","20%" }
} },
{"text",new Dictionary<string,dynamic>(){
{ "attrName", null },
{ "isCss", "False" },
{ "turnedOn","True" },
{ "text","" }
} },
{"href",new Dictionary<string,dynamic>(){
{ "attrName", null },
{ "isCss", "False" },
{ "flags", "removeAttrIfTurnedOff" },
{ "turnedOn","True" },
{ "href","about:blank" }
} }
};
var cln=clone(buildInfoDict);
public static dynamic clone(dynamic obj)
{
dynamic cloneObj = null;
if (IsAssignableFrom(obj, typeof(IDictionary)))
{
cloneObj = Activator.CreateInstance(obj.GetType());
foreach (var key in obj.Keys)
{
cloneObj[key] = clone(obj[key]);
}
}
else if (IsNumber(obj) || obj.GetType() == typeof(string))
{
cloneObj = obj;
}
else
{
Debugger.Break();
}
return cloneObj;
}
public static bool IsAssignableFrom(this object obj, Type ObjType = null, Type ListType = null, bool HandleBaseTypes = false)
{
if (ObjType == null)
{
ObjType = obj.GetType();
}
bool Res;
do
{
Res = (ObjType.IsGenericType && ObjType.GetGenericTypeDefinition().IsAssignableFrom(ListType)) ||
(ListType == null && ObjType.IsAssignableFrom(obj.GetType()));
ObjType = ObjType.BaseType;
} while ((!Res && ObjType != null) && HandleBaseTypes && ObjType != typeof(object));
return Res;
}
public static bool IsNumber(this object value)
{
return value is sbyte
|| value is byte
|| value is short
|| value is ushort
|| value is int
|| value is uint
|| value is long
|| value is ulong
|| value is float
|| value is double
|| value is decimal;
}
Here is another way to clone a dictionary, assuming you know to do the "right" thing as far as handling whatever is hiding behind the "T" (a.k.a. "object") in your specific circumstances.
internal static Dictionary<string, object> Clone(Dictionary<string, object> dictIn)
{
Dictionary<string, object> dictOut = new Dictionary<string, object>();
IDictionaryEnumerator enumMyDictionary = dictIn.GetEnumerator();
while (enumMyDictionary.MoveNext())
{
string strKey = (string)enumMyDictionary.Key;
object oValue = enumMyDictionary.Value;
dictOut.Add(strKey, oValue);
}
return dictOut;
}
I would evaluate if T was a value or reference type. In the case T was a value type I would use the constructor of Dictionary, and in the case when T was a reference type I would make sure T inherited from ICloneable.
It will give
private static IDictionary<string, T> Copy<T>(this IDictionary<string, T> dict)
where T : ICloneable
{
if (typeof(T).IsValueType)
{
return new Dictionary<string, T>(dict);
}
else
{
var copy = new Dictionary<string, T>();
foreach (var pair in dict)
{
copy[pair.Key] = pair.Value;
}
return copy;
}
}
© 2022 - 2024 — McMap. All rights reserved.
entry.Value
value might be yet another [sub]collection. – Mantellone