簡體   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