克隆/深复制.NET通用词典的最佳方法是什么?

时间:2020-03-06 14:47:05  来源:igfitidea点击:

我有一个通用的字典Dictionary,我想从本质上提出..any建议的Clone()。

解决方案

(注意:尽管克隆版本可能有用,但对于简单的浅表副本,我在另一篇文章中提到的构造函数是一个更好的选择。)

我们希望副本有多深,使用的是.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());

(那些未经测试,但应该可以使用。)

好的,.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()"是一个适当的深度克隆。

对于.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",否则,通用实现根本不可行。

我们可以始终使用序列化。我们可以序列化对象,然后反序列化它。这将为我们提供《词典》及其中所有项目的详尽副本。现在,我们可以创建任何标记为[可序列化]的对象的深层副本,而无需编写任何特殊代码。

这是将使用二进制序列化的两种方法。如果使用这些方法,则只需调用

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;
}

二进制序列化方法可以正常工作,但是在我的测试中,它显示出比非串行化克隆慢10倍。在`Dictionary <string,List <double >>'上进行了测试

Dictionary<string, int> dictionary = new Dictionary<string, int>();

Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);