【问题标题】:C# dictionary value clearing out when I clear list previously assigned to it....why?当我清除以前分配给它的列表时,C# 字典值清除....为什么?
【发布时间】:2011-07-07 02:14:45
【问题描述】:
Dictionary <string, List <SaleItem>> saleItemNew = new Dictionary<string, List<    SaleItem>> ();

saleItems = new List <SaleItem> ();

saleItemNew.Add("1", saleItems);

此时字典中的列表有值了。

saleItems.Clear();

但是,当我清除之前分配给它的列表时,字典的值 List 现在是空的...为什么?

【问题讨论】:

    标签: c# dictionary


    【解决方案1】:

    字典包含对列表的相同引用,因此修改列表将更改两个引用。

    关于引用类型的 Microsoft 文档:http://msdn.microsoft.com/en-us/library/490f96s2.aspx

    【讨论】:

    • 我假设列表是一样的?
    • 是的,他们是。修改引用的任何人都会为使用该引用的每个人修改它。将引用视为指向底层列表的指针。
    • 说到这个,如果你想添加很多不共享相同引用的列表,只需执行“new List()”并在每次需要时将其添加到字典中一个新列表。
    【解决方案2】:

    原因是 Dictionary 是一个引用而不是值类型。当您将 Dictionary 分配给另一个变量时,它不会执行深层复制。相反,它只是将另一个引用指向同一个对象。由于只有一个对象,因此通过任一引用清除对两个引用都是可见的。

    这与 .Net Framework 中的值类型不同。值类型的赋值本质上是执行数据的浅拷贝并创建两个独立的对象。注意,如果值类型有一个引用字段,那么两个值类型中的两个字段仍然会指向同一个对象。

    【讨论】:

      【解决方案3】:

      它与内存使用和指针有关。在为对象分配内存时,您有一个堆栈和一个堆,该内存就是堆之一。您的 saleItems 变量在堆栈上定义并指向堆上的内存地址。您的字典也在指向堆的堆栈上。

      当你说:

      saleItems = new List<SaleItem>()
      

      变量 saleItems 被压入堆栈并包含指向堆上数据位置的内存地址。可以说0x0100。现在您将一个新的DictionaryItem 添加到您的字典中。 DictionaryItem 放置在堆上,具有两个属性,键和值。在这种情况下,您已将saleItems 添加为Value,因此Value 也具有地址0x0100。现在DictionaryItem.Value 指向与saleItems 相同的内存。当您调用 saleItems.Clear 时,您是说在地址 0x0100 找到列表并删除所有项目。所以字典和变量都是空的,因为它们指向同一个内存。你想要做的是再次说saleItems = new List&lt;SaleItem&gt;();。现在 saleItems 将指向堆上的一个新地址(比如0x0200)。 DictionaryItem.Value 仍然指向内存地址 0x0100,因此您可以对 saleItems 变量进行操作,而不会影响字典中的数据。

      有关 c# 中的堆栈和堆的更多信息,请阅读这篇文章:http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.aspx?ArticleID=9adb0e3c-b3f6-40b5-98b5-413b6d348b91

      【讨论】:

      • 这些是实现细节。这里的重点是“值类型”与“引用类型”,而不是它们如何在内部实现的细节。
      • IMO - 除非您了解底层内存的使用方式,否则“值类型”和“引用类型”绰号毫无意义,这需要了解堆栈和堆及其关系。类、委托等都是引用类型,但是引用类型是什么意思。这意味着堆栈上的内存用于引用堆中的内存地址。整数、布尔值、枚举都是值类型,但这是什么意思呢?这意味着在堆栈上使用内存来存储真实值。 IMO 理解这一点至关重要。
      【解决方案4】:

      将列表添加到字典中只是浅拷贝...不会创建和添加具有相同值的新列表(深拷贝);而是添加了对旧列表的引用。

      【讨论】:

        【解决方案5】:

        它使用相同的引用。

        更好的方法是

        Dictionary <string, List <SaleItem>> saleItemNew = new Dictionary<string, List<SaleItem>>();
        saleItemNew.Add("1", new List<SaleItem>());
        

        为了清算

        saleItemNew["1"] = new List<SaleItem>(); 
        

        【讨论】:

          【解决方案6】:

          因为它是一个引用类型,所以只复制指向内存中值的指针,而不是值本身。 您可以使用构造函数指定您想要的行为:

          来自 dot net perls: // // 将字典复制到第二个对象。 // 字典副本 = new Dictionary(dictionary);

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-01-08
            • 2018-11-03
            • 1970-01-01
            • 2021-12-09
            • 1970-01-01
            • 2016-09-08
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多