C#字典的奇怪行为
本文关键字:字典 | 更新日期: 2023-09-27 18:23:59
我有以下简化程序
using System;
using System.Collections.Generic;
using System.Text;
class ItemClass {
public int Id = 0;
public int[] Childs = new int[] { };
public int Count = 0;
}
class Class1 {
Dictionary<int, ItemClass> _Items = new Dictionary<int, ItemClass> { };
private void AddRecursive(int ItemID, int count, ref Dictionary<int, ItemClass> ItemList) {
if (!_Items.ContainsKey(ItemID)) {
return;
}
ItemClass _item = _Items[ItemID];
if (!ItemList.ContainsKey(ItemID)) {
ItemList.Add(ItemID, _item);
}
ItemList[ItemID].Count += count;
if (_item.Childs.Length > 0) {
foreach (int tmpItem in _item.Childs) {
AddRecursive(tmpItem, ItemList[ItemID].Count, ref ItemList);
}
}
}
public void Add(int item, int[] childs) {
if (!_Items.ContainsKey(item)) {
_Items.Add(item, new ItemClass() { Id = item, Childs = childs, Count = 0 });
}
}
public Dictionary<int, ItemClass> MakeList(int ItemID) {
if (!_Items.ContainsKey(ItemID)) {
return new Dictionary<int, ItemClass> { };
}
Dictionary<int, ItemClass> ItemList = new Dictionary<int, ItemClass> { };
AddRecursive(ItemID, 1, ref ItemList);
return ItemList;
}
}
class Program {
static void Main(string[] args) {
Class1 class1 = new Class1();
class1.Add(1111, new int[] { });
class1.Add(2222, new int[] { 1111 });
class1.Add(3333, new int[] { 1111, 2222 });
Dictionary<int, ItemClass> items1 = class1.MakeList(3333);
foreach (ItemClass item in items1.Values) {
Console.WriteLine(item.Id + " " + item.Count);
}
Console.WriteLine("");
Dictionary<int, ItemClass> items2 = class1.MakeList(3333);
foreach (ItemClass item in items2.Values) {
Console.WriteLine(item.Id + " " + item.Count);
}
Console.ReadKey();
}
}
它有一个简单的任务,即计数项目并显示项目列表及其计数。当我第一次调用MakeList
函数时,结果是意料之中的。
预期:
3333 1
1111 2
2222 1
3333 1
1111 2
2222 1
实际
3333 1
1111 2
2222 1
3333 2
1111 7
2222 3
当我重新声明变量ItemList
时,我希望在第二次调用该函数时看到相同的结果,但这就像上次调用的结果被缓存并重复使用一样。
为什么会发生这种情况,为什么会有这种行为?有什么办法可以避免吗?
实际上它并没有什么奇怪的。当您调用AddRecursive
方法时,您刚刚修改了ItemClass
对象中Count
属性的值。
假设您真的想得到您想要的,您只需要深度克隆ItemClass
对象,或者只需创建新实例并复制属性的原始值。
ItemClass _item = new ItemClass() { Childs = _Items[ItemID].Childs, Count = _Items[ItemID].Count, Id = _Items[ItemID].Id };
而不是这个
Itemclass _item = _Items[ItemId]
您正在声明ItemList
,但使用来自内部_Items
:ItemClass _item = _Items[ItemID];
的相同对象,并对相同对象递增计数。这就是为什么部分:)。避免的部分可能是创建新项目。
您的问题是在运行AddRecursive
时更改了_Items
字典中ItemClass
实例的Count
属性。
去掉可变的Count
属性(它实际上不应该在ItemClass
中),并将代码简化为
class ItemClass
{
public int Id = 0;
public int[] Childs = new int[] { };
}
class Class1
{
Dictionary<int, ItemClass> _Items = new Dictionary<int, ItemClass>();
private void AddRecursive(int itemId, Dictionary<int, int> itemList)
{
if (!_Items.ContainsKey(itemId))
return;
if (!itemList.ContainsKey(itemId))
itemList.Add(itemId, 1);
else
itemList[itemId] += 1;
var item = _Items[itemId];
if (item.Childs.Length > 0)
foreach (int tmpItem in item.Childs)
AddRecursive(tmpItem, itemList);
}
public void Add(int item, int[] childs)
{
if (!_Items.ContainsKey(item))
_Items.Add(item, new ItemClass() { Id = item, Childs = childs });
}
public Dictionary<int, int> MakeList(int itemId)
{
if (!_Items.ContainsKey(itemId))
return new Dictionary<int, int>();
var itemList = new Dictionary<int, int>();
AddRecursive(itemId, itemList);
return itemList;
}
}