繁体   English   中英

C#字典的奇怪行为

[英]Strange behavior of C# Dictionary

我有以下简化程序

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 ,我期望第二次调用该函数时看到相同的结果,但是就像先前调用的结果被缓存并重新使用一样。

为什么会这样,为什么会这样? 有什么办法可以避免呢?

您重新声明ItemList ,但使用内部_Items相同对象: ItemClass _item = _Items[ItemID]; 并增加对同一对象的计数。 这就是为什么part :)。 避免部分可能是创建新项目。

其实没有什么奇怪的。 您刚刚在调用AddRecursive方法时修改了ItemClass对象中Count属性的值。

假设您确实想要获得期望的结果,则只需要深度克隆ItemClass对象或简单地创建新实例并复制属性的原始值即可。

ItemClass _item = new ItemClass() { Childs = _Items[ItemID].Childs, Count = _Items[ItemID].Count, Id = _Items[ItemID].Id };

代替这个

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;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM