【问题标题】:How do you clone a dictionary in .NET?如何在 .NET 中克隆字典?
【发布时间】:2011-01-17 18:54:25
【问题描述】:

我知道我们应该使用字典而不是哈希表。我找不到克隆字典的方法。即使将其转换为 ICollection 以获取 SyncRoot,我知道这也是不受欢迎的。

我现在正忙着改变它。我是否正确假设没有办法以通用方式实现任何类型的克隆,这就是字典不支持克隆的原因?

【问题讨论】:

  • 我看到了,但我不关心深拷贝。克隆浅拷贝就可以了。我的问题还有第二部分:没有克隆的原因是因为泛型引入的困难吗?

标签: .net data-structures


【解决方案1】:

这是我曾经写过的一个快速而肮脏的克隆方法……我认为最初的想法来自 CodeProject。

Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary

Public Shared Function Clone(Of T)(ByVal inputObj As T) As T
    'creating a Memorystream which works like a temporary storeage '
    Using memStrm As New MemoryStream()
        'Binary Formatter for serializing the object into memory stream '
        Dim binFormatter As New BinaryFormatter(Nothing, New StreamingContext(StreamingContextStates.Clone))

        'talks for itself '
        binFormatter.Serialize(memStrm, inputObj)

        'setting the memorystream to the start of it '
        memStrm.Seek(0, SeekOrigin.Begin)

        'try to cast the serialized item into our Item '
        Try
            return DirectCast(binFormatter.Deserialize(memStrm), T)
        Catch ex As Exception
            Trace.TraceError(ex.Message)
            return Nothing
        End Try
    End Using
End Function

用途:

Dim clonedDict As Dictionary(Of String, String) = Clone(Of Dictionary(Of String, String))(yourOriginalDict)

【讨论】:

    【解决方案2】:

    使用接受字典的构造函数。看这个例子

    var dict = new Dictionary<string, string>();
    
    dict.Add("SO", "StackOverflow");
    
    var secondDict = new Dictionary<string, string>(dict);
    
    dict = null;
    
    Console.WriteLine(secondDict["SO"]);
    

    只是为了好玩.. 您可以使用 LINQ!这是一个更通用的方法。

    var secondDict = (from x in dict
                      select x).ToDictionary(x => x.Key, x => x.Value);
    

    编辑

    这应该适用于引用类型,我尝试了以下方法:

    internal class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public User Parent { get; set; }
    }
    

    以及上面修改过的代码

    var dict = new Dictionary<string, User>();
    
    dict.Add("First", new User 
        { Id = 1, Name = "Filip Ekberg", Parent = null });
    
    dict.Add("Second", new User 
        { Id = 2, Name = "Test test", Parent = dict["First"] });
    
    var secondDict = (from x in dict
                      select x).ToDictionary(x => x.Key, x => x.Value);
    
    dict.Clear();
    
    dict = null;
    
    Console.WriteLine(secondDict["First"].Name);
    

    输出“Filip Ekberg”。

    【讨论】:

    • 请记住,第一种方法将创建一个浅拷贝,即对象也不会被拷贝。对于不是真正问题的字符串,但对于其他引用类型可能是。
    • 使用 LINQ 表达式,它至少应该复制引用。当 GC 找到 dict 并且它为 null,但引用不是,它们不应该被删除,对吗?所以它应该也适用于引用类型。
    • 值得注意的是:这种方法不会克隆源IDictionaryIEqualityComparer,即如果您有一个IDictionaryStringComparer.OrdinalIgnoreCase
    • 第一个例子也不应该说“dict = null;”但是“dict.clear();”真正证明新的不仅仅是参考。
    • 您的参考示例具有误导性/不正确 - 两个集合中的引用类型仍然是相同的实例:dotnetfiddle.net/AMRtta -- 更改 dict["First"].Name 并且它也将在 secondDict["First"].Name 中更改。从一个集合中删除它与修改它不同。另外,如果你要使用 Linq:只需 dict.ToDictionary 而不是 (from x in dict select x).ToDictionary
    【解决方案3】:

    只是因为任何人都需要 vb.net 版本

    Dim dictionaryCloned As Dictionary(Of String, String)
    dictionaryCloned  = (From x In originalDictionary Select x).ToDictionary(Function(p) p.Key, Function(p) p.Value)
    

    【讨论】:

      【解决方案4】:

      对于原始类型字典

      Public Sub runIntDictionary()
        Dim myIntegerDict As New Dictionary(Of Integer, Integer) From {{0, 0}, {1, 1}, {2, 2}}
        Dim cloneIntegerDict As New Dictionary(Of Integer, Integer)
        cloneIntegerDict = myIntegerDict.Select(Function(x) x.Key).ToList().ToDictionary(Of Integer, Integer)(Function(x) x, Function(y) myIntegerDict(y))
      End Sub
      

      对于实现 ICloneable 的 Object 的字典

      Public Sub runObjectDictionary()
        Dim myDict As New Dictionary(Of Integer, number) From {{3, New number(3)}, {4, New number(4)}, {5, New number(5)}}
        Dim cloneDict As New Dictionary(Of Integer, number)
        cloneDict = myDict.Select(Function(x) x.Key).ToList().ToDictionary(Of Integer, number)(Function(x) x, Function(y) myDict(y).Clone)
      End Sub
      
      Public Class number
        Implements ICloneable
        Sub New()
        End Sub
        Sub New(ByVal newNumber As Integer)
          nr = newnumber
        End Sub
        Public nr As Integer
      
        Public Function Clone() As Object Implements ICloneable.Clone
          Return New number With {.nr = nr}
        End Function
        Public Overrides Function ToString() As String
          Return nr.ToString
        End Function
      End Class
      

      【讨论】:

        【解决方案5】:

        对于简单的字典

        public static Dictionary<string, object> DictionaryClone(Dictionary<string, object> _Datas)
        {
            Dictionary<string, object> output = new Dictionary<string, object>();
        
            if (_Datas != null)
            {
                foreach (var item in _Datas)
                    output.Add(item.Key, item.Value);
            }
        
            return output;
        }
        

        【讨论】:

          猜你喜欢
          • 2020-10-15
          • 1970-01-01
          • 1970-01-01
          • 2012-10-09
          • 1970-01-01
          • 1970-01-01
          • 2011-02-07
          • 2010-11-21
          • 2021-09-16
          相关资源
          最近更新 更多