Dictionary <string, List <SaleItem>> saleItemNew = new Dictionary<string, List< SaleItem>> ();
saleItems = new List <SaleItem> ();
saleItemNew.Add("1", saleItems);
此时,词典中的列表具有值。
saleItems.Clear();
但是,当我清除之前分配给它的列表时,字典的值列表现在为空......为什么?
答案 0 :(得分:11)
字典包含对列表的相同引用,因此修改列表将更改两个引用。
有关参考类型的Microsoft文档:http://msdn.microsoft.com/en-us/library/490f96s2.aspx
答案 1 :(得分:1)
原因是Dictionary是引用而不是值类型。将Dictionary分配给另一个变量时,它不会执行深层复制。相反,它只是指向同一对象的另一个引用。由于只有一个对象,因此两个引用都可以看到通过任一引用清除。
这与.Net Framework中的值类型形成对比。值类型的赋值实质上执行数据的浅表副本并创建两个独立对象。请注意,如果值类型具有引用字段,则两个值类型中的两个字段仍将指向同一对象。
答案 2 :(得分:0)
它与内存使用和指针有关。在为对象分配内存时,您有一个堆栈和一个堆,该内存是堆的内存。您的saleItems变量在堆栈上定义,并指向堆上的内存地址。你的词典也在堆栈上指向堆。
当你说:
saleItems = new List<SaleItem>()
变量saleItems被压入堆栈并包含一个内存地址,指向堆上数据的位置。让我们说0x0100
。现在,您将新的DictionaryItem
添加到字典中。 DictionaryItem
放在堆上,具有两个属性Key和Value。在这种情况下,您已将saleItems
添加为Value
,因此Value
也具有地址0x0100
。现在DictionaryItem.Value
指向与saleItems相同的内存。当您调用saleItems.Clear时,您说要在地址0x0100
找到列表并删除所有项目。所以字典和变量都变空了,因为它们指向同一个内存。你想要做的是再次说saleItems = new List<SaleItem>();
。现在,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
答案 3 :(得分:0)
将列表添加到字典只是一个浅层副本...不会创建和添加具有相同值的新列表(深层副本);而是添加了对旧列表的引用。
答案 4 :(得分:0)
它使用相同的参考。
更好的方法是
Dictionary <string, List <SaleItem>> saleItemNew = new Dictionary<string, List<SaleItem>>();
saleItemNew.Add("1", new List<SaleItem>());
清算
saleItemNew["1"] = new List<SaleItem>();
答案 5 :(得分:0)
因为它是一个引用类型,所以只复制指向内存中值的指针而不是值本身。 您可以使用构造函数指定所需的行为:
来自dot net perls: // //将Dictionary复制到第二个对象。 // 字典副本=新词典(字典);