【发布时间】:2016-07-14 09:47:07
【问题描述】:
我有一个通用字典Dictionary<string, T>,我想从本质上提出一个 Clone() 的 ..any 建议。
【问题讨论】:
标签: c# generics collections clone
我有一个通用字典Dictionary<string, T>,我想从本质上提出一个 Clone() 的 ..any 建议。
【问题讨论】:
标签: c# generics collections clone
这是一些真正的“真正的深度复制”,不知道类型,但有一些递归遍历,适合初学者。它适用于嵌套类型和我认为几乎所有棘手的类型。我还没有添加嵌套数组处理,但是您可以根据自己的选择进行修改。
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;
}
【讨论】:
如果您有一个“对象”字典,并且对象可以是任何类似的东西(double、int、...或 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) );
【讨论】:
这对我有帮助,当我尝试深度复制 Dictionary
Dictionary<string, string> dict2 = new Dictionary<string, string>(dict);
祝你好运
【讨论】:
这对我来说很好用
// assuming this fills the List
List<Dictionary<string, string>> obj = this.getData();
List<Dictionary<string, string>> objCopy = new List<Dictionary<string, string>>(obj);
正如 Tomer Wolberg 在 cmets 中所描述的,如果值类型是可变类,这将不起作用。
【讨论】:
回复旧帖子,但我发现将其包装如下很有用:
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;
}
}
【讨论】:
好的,.NET 2.0 的答案:
如果您不需要克隆值,您可以使用构造函数重载到 Dictionary,它采用现有的 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() 是一个合适的深度克隆。
【讨论】:
entry.Value 值可能是另一个 [子] 集合。
Clone() 方法是深还是浅。我已经为此添加了注释。
ConcurrentDictionary。
如果键/值是 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;
}
【讨论】:
对我来说最好的方法是:
Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);
【讨论】:
new 字典(注意关键字“new”)并用旧对象的值填充它。对于 (注意:虽然克隆版本可能有用,但对于简单的浅拷贝,我在另一篇文章中提到的构造函数是更好的选择。)
您希望副本有多深,以及您使用的是什么版本的 .NET?如果您使用 .NET 3.5,我怀疑对 ToDictionary 的 LINQ 调用(同时指定键和元素选择器)将是最简单的方法。
例如,如果您不介意该值是浅克隆:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => entry.Value);
如果您已经约束 T 来实现 ICloneable:
var newDictionary = oldDictionary.ToDictionary(entry => entry.Key,
entry => (T) entry.Value.Clone());
(那些未经测试,但应该可以工作。)
【讨论】:
二进制序列化方法工作正常,但在我的测试中,它显示比克隆的非序列化实现慢 10 倍。在Dictionary<string , List<double>>上测试过
【讨论】:
ToBinary() 中,Serialize() 方法是用this 而不是yourDictionary 调用的。然后在FromBinary() 中,首先将 byte[] 手动复制到 MemStream 但它可以只提供给它的构造函数。
Dictionary<string, int> dictionary = new Dictionary<string, int>();
Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
【讨论】:
您总是可以使用序列化。您可以序列化对象然后反序列化它。这将为您提供字典的深层副本以及其中的所有项目。现在您可以创建任何标记为 [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;
}
【讨论】:
对于 .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,否则泛型实现根本不实用。
【讨论】: