243

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

4

12 回答 12

246

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

您希望副本有多深,以及您使用的是什么版本的 .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());

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

于 2008-09-26T13:53:05.577 回答
199

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

于 2008-09-26T14:22:46.147 回答
103
Dictionary<string, int> dictionary = new Dictionary<string, int>();

Dictionary<string, int> copy = new Dictionary<string, int>(dictionary);
于 2010-11-24T10:51:19.750 回答
22

当我尝试深度复制 Dictionary < string, string > 时,这对我有帮助

Dictionary<string, string> dict2 = new Dictionary<string, string>(dict);

祝你好运

于 2020-05-10T05:58:40.050 回答
11

对于 .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方法来克隆字典。当然,这个实现需要字典的值类型 implements ICloneable,否则泛型实现根本不实用。

于 2008-09-26T15:09:44.100 回答
9

这对我来说很好

 // 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 在评论中所描述的,如果值类型是可变类,这将不起作用。

于 2018-03-22T13:33:58.170 回答
7

你总是可以使用序列化。您可以序列化对象然后反序列化它。这将为您提供字典的深层副本以及其中的所有项目。现在,您可以创建任何标记为 [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;
}
于 2008-09-26T15:35:44.100 回答
6

对我来说最好的方法是:

Dictionary<int, int> copy= new Dictionary<int, int>(yourListOrDictionary);
于 2015-09-08T07:15:47.257 回答
3

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

于 2009-09-30T16:07:58.447 回答
0

如果键/值是 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;
    }
于 2016-08-23T19:13:00.637 回答
0

如果您有一个“对象”字典,并且对象可以是任何类似(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) );


于 2020-10-14T14:00:05.900 回答
0

这是一些真正的“真正的深度复制”,不知道类型和一些递归遍历,对初学者有好处。它适用于嵌套类型和我认为几乎所有棘手的类型。我还没有添加嵌套数组处理,但您可以根据自己的选择进行修改。

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;
}
于 2021-10-13T15:23:36.753 回答