C# 克隆/深度复制 .NET 通用 Dictionary<string, T> 的最佳方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/139592/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:10:23  来源:igfitidea点击:

What is the best way to clone/deep copy a .NET generic Dictionary<string, T>?

提问by mikeymo

I've got a generic dictionary Dictionary<string, T>that I would like to essentially make a Clone() of ..any suggestions.

我有一个通用字典Dictionary<string, T>,我想基本上制作一个 Clone() 的 ..any 建议。

采纳答案by Jon Skeet

Okay, the .NET 2.0 answers:

好的,.NET 2.0 回答:

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.)

如果您不需要克隆值,您可以使用构造函数重载到字典,它采用现有的 IDictionary。(您也可以将比较器指定为现有字典的比较器。)

If you doneed 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.

当然,这也取决于TValue.Clone()是一个合适的深度克隆。

回答by Jon Skeet

(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.

您希望副本有多深,您使用的是什么版本的 .NET?我怀疑如果您使用 .NET 3.5,对 ToDictionary 的 LINQ 调用(指定键和元素选择器)将是最简单的方法。

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:

如果您已经约束 T 来实现 ICloneable:

var newDictionary = oldDictionary.ToDictionary(entry => entry.Key, 
                                               entry => (T) entry.Value.Clone());

(Those are untested, but should work.)

(那些未经测试,但应该可以工作。)

回答by Compile This

For .NET 2.0 you could implement a class which inherits from Dictionaryand implements ICloneable.

对于 .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;
    }
}

You can then clone the dictionary simply by calling the Clonemethod. Of course this implementation requires that the value type of the dictionary implements ICloneable, but otherwise a generic implementation isn't practical at all.

然后,您只需调用该Clone方法即可克隆字典。当然,这个实现需要字典的值类型实现ICloneable,否则泛型实现根本不实用。

回答by Shaun Bowe

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.

你总是可以使用序列化。您可以序列化对象然后反序列化它。这将为您提供字典及其中所有项目的深层副本。现在,您可以创建任何标记为 [Serializable] 的对象的深层副本,而无需编写任何特殊代码。

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

回答by loty

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

二进制序列化方法工作正常,但在我的测试中,它比克隆的非序列化实现慢 10 倍。测试了一下Dictionary<string , List<double>>

回答by Herald Smit

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

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

回答by nikssa23

The best way for me is this:

对我来说最好的方法是这样的:

Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);

回答by Arvind

Try this if key/values are ICloneable:

如果键/值是 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;
    }

回答by Decaf Sux

Replying on old post however I found it useful to wrap it as follows:

回复旧帖子,但我发现将其包装如下很有用:

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

回答by BonifatiusK

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.

正如 Tomer Wolberg 在评论中所描述的,如果值类型是可变类,这将不起作用。