将元素添加到列表中,包括字典会产生意外结果C#

时间:2019-05-14 15:21:45

标签: c# list dictionary collections

我正在将后端转换为c#,并且发现了奇怪的行为

当我在字典中的列表中添加元素

(实际上在另一本词典中):

不久,它将值添加到字典中每个元素的每个列表中。

代码如下:

       public class Validator_Counter_Model
        {
            public readonly  Dictionary<string,Info_Model> Info;
            private Dictionary<string,Dictionary<DateTime,List<int>>> _map = new Dictionary<string, Dictionary<DateTime,List<int>>>();
            public Validator_Counter_Model(Dictionary<string, Info_Model> info)
            {
                Info = info;
            }
            public void Add(Validation_Element element)
            {

/// #### PROBLEM IS HERE!
                if (!_map.ContainsKey(element.Id))
                {
                    Dictionary<DateTime, List<int>> newmap = new Dictionary<DateTime, List<int>>();
                    _map.Add(element.Id, newmap);
                }

                DateTime fulldate = new Custom_Time_Model(element.Time).RegularTime;
                if (!_map[element.Id].ContainsKey(fulldate.Date))
                {
                    List<int> newList = new List<int>();
                    _map[element.Id].Add(fulldate.Date, newList);
                }
                _map[element.Id][fulldate.Date].Add(element.Time);
/// #### PROBLEM IS HERE!

            }

            public void Del(Validation_Element element)
            {
                DateTime fulldate = new Custom_Time_Model(element.Time).RegularTime;
                DateTime date = new DateTime(fulldate.Year, fulldate.Month, fulldate.Day);
                _map[element.Id][date].Remove(element.Time);
            }

            public void Update(Dictionary<string, Dictionary<DateTime, List<int>>> newMap) => _map = newMap;

            public Dictionary<string, Dictionary<DateTime, List<int>>> map => _map;

        }
    }

2 个答案:

答案 0 :(得分:0)

鉴于字典键是stringDateTime之类的已知类型,我可以填写缺失类的实现,而具体细节并不重要。我不在乎它们是否包含有意义的值。我只想看看一切如何。这些都贴在最后:

现在可以编写一个单元测试,以查看您所描述的情况是否正在发生。

[TestMethod]
public void validation_elements_are_added_to_only_one_dictionary()
{
    var elementOne = new Validation_Element {Id = "A", Time = 1 };
    var elementTwo = new Validation_Element { Id = "B" , Time = 2};
    var elementThree = new Validation_Element { Id = "A" , Time = 3};

    var subject = new Validator_Counter_Model(new Dictionary<string, Info_Model>());
    subject.Add(elementOne);
    subject.Add(elementTwo);
    subject.Add(elementThree);

    var output = subject.map;

    var elementsWithId_A = output["A"];
    var elementsWithId_B = output["B"];

    var id_a_innerList = elementsWithId_A[new DateTime(2000, 1, 1)];
    var id_b_innerList = elementsWithId_B[new DateTime(2000, 1, 1)];

    Assert.AreEqual(2, id_a_innerList.Count);
    Assert.AreEqual(1, id_b_innerList.Count);
}

我要添加两个带有“ A”的验证元素和一个带有“ B”的验证元素。这意味着_map应该包含两个字典。内部字典的键将始终为1/1/2000,因此将有两个内部列表。

我期望的是A的内部列表将包含两个项目,B的内部列表将包含一个项目。如果每个项目都添加到每个列表中,那么它们都会有两个。

测试通过了,在这种情况下是可以预期的。仅通过查看代码,我们可以看到Add正在创建不同的列表,并且不会将项目添加到两个列表中。但是现在测试证实了这一点。

这意味着,如果您看到项目被添加到多个列表中,那么问题就出在您想像的地方。它必须在其他地方。那是关于单元测试的很棒的事情之一。它们使我们对代码的某个区域具有一定的确定性,因此,如果某些地方不起作用,我们知道问题可能出在没有单元测试的区域。缩小搜索范围可以更快,更轻松地发现错误。

如果我们确实发现单元测试有问题,那么我们可以只调试该单元测试,而不必调试整个应用程序。然后想象一下其他类是否也有单元测试。在编写代码时,我们总是会犯错误,但是通过单元测试,我们可以更快地发现它们并更轻松地解决它们。

在这种情况下,我弄虚了您的类的实现有些混乱。尽管我认为这仅仅是数据,但我认为这没有什么不同,但确实会带来很小程度的不确定性。我会用真实的替换它们,然后相应地调整测试。您可以根据需要编写更多测试。


未提供的类的有效实现:

public class Validation_Element
{
    public string Id { get; set; }
    public int Time { get; set; }
}

public class Custom_Time_Model
{
    public Custom_Time_Model(int time)
    {
        Time = time;
        // This makes it possible to create classes where `Time` is different
        // but fullDate.Date (in the Add method) is the same. If I want that date
        // to be different I'll add 24 or more hours.
        RegularTime = new DateTime(2000,1,1).AddHours(time);
    }
    public DateTime RegularTime { get; set; }
    public int Time { get; set; }
}

public class Info_Model { }

答案 1 :(得分:0)

找到了答案HERE

基本上是第二个字典(第一个字典中的那个) 本身不是“字典”,而是另一本字典的参考 这就是为什么在列表中添加值会更改每个键的所有列表