代码之家  ›  专栏  ›  技术社区  ›  Rachel

是否有任何原因在该代码块的List<T>中找不到现有项?

  •  9
  • Rachel  · 技术社区  · 11 年前

    我们有一个网格 List<T> 共个项目。每当用户点击“刷新”时,就会从数据库中获取更改,并更新绑定列表。我遇到了一个问题,重复的项目被添加到网格中,我不知道为什么。

    数据库调用返回两个值: List<int> 已更改的记录ID,以及 List<MyClass> 已更改记录的更新数据。我正在调试的现有代码发现需要更新的内容如下:

    public void FindUpdates(IList<MyClass> existingRecords,
                        IList<MyClass> updatedRecords,
                        List<int> updatedIds,
                        out IDictionary<int, int> existing,
                        out IDictionary<int, int> updated,
                        out List<int> updates,
                        out List<int> removes,
                        out List<int> adds)
    {
        updates = new List<int>();
        removes = new List<int>();
        adds = new List<int>();
    
        existing = FindUpdated(existingRecords, updatedIds);
        updated = FindUpdated(updatedRecords, updatedIds);
    
        if (updatedIds != null)
        {
            // split add/update and remove
            foreach (int id in updatedIds)
            {
                if (!existing.ContainsKey(id))
                    adds.Add(id);
                else if (updated.ContainsKey(id))
                    updates.Add(id);
                else
                    removes.Add(id);
            }
    
            WriteToLog(updatedIds, adds, updates, removes);
        }
    }
    
    private IDictionary<int, int> FindUpdated(IList<MyClass> records, List<int> updatedIds)
    {
        IDictionary<int, int> foundItems = new Dictionary<int, int>();
    
        if (records != null && updatedIds != null)
        {
            for (int i = 0; i < records.Count; i++)
            {
                IMyClass r = records[i] as IMyClass ;
                if (r != null && !r.IsDisposed)
                {
                    if (updatedIds.Contains(r.Id))
                    {
                        foundItems.Add(r.Id, i);
                    }
                }
            }
        }
    
        return foundItems;
    }
    

    调用的结果 FindUpdates() 我有一个 Dictionary<Id, Data> 现有记录,a 字典<Id、数据> 要替换的更新记录的,以及 列表<int> 应从数据源中添加、删除或更新项目的ID。

    有时,一条记录会被添加到网格中两次,而我一辈子都无法弄清楚这段代码哪里出了问题。

    我从其中一个实例中提取了日志文件,可以清楚地看到以下事件序列:

    • 项目#2添加到数据列表
    • 20分钟后,项目#2再次添加到数据列表中

    WriteToLog() 从第二个加法告诉我

    • updatedIds 包含值1、2和3
    • adds 包含1和2
    • updates 包含3

    根据其他日志条目,我可以清楚地看到项目#2是以前添加的,从未删除过,因此它应该在 existingRecords 变量已显示在 更新 变量,不在 添加 此外,项目#2在第一次添加和第二次添加之间成功更新了几次,因此理论上代码应该可以工作。我还有一个UI截图,在数据网格中显示了项目#2的两个副本。

    笔记。。。

    • IsDisposed 仅在重写的 .Dispose() 方法。我认为这不会发生。

      编辑: 从那时起,我添加了一个日志语句,可以验证 已处理 未设置为 true 当这种情况发生时。

    • 这种情况在少数不同的用户身上已经发生过几次了,所以这不仅仅是一次性的事情。但我无法按需再现问题。

    • 记录网格可能相当大,平均有几千项。

    • 我还没有排除DB调用返回无效值或不具有相同项的列表的想法,但是我不知道这会如何影响结果

    • 有一次我能够看到这个bug在运行,我们正在运行一些测试,其他用户相当频繁地修改记录#2

    • 这一切都在后台线程中运行

    • 根据日志,当时只运行了一次。它在前一分钟运行,后两分钟运行。

    • 从日志文件中,我可以看到项目#2在第二次被错误添加之前已经被正确更新了几次,所以这段代码在几次之前确实使用了现有的数据集。

    上面显示的代码中是否有任何可能导致这种情况发生的原因?或者可能是C#中一个罕见的已知问题,我不知道这可能会发生?

    2 回复  |  直到 10 年前
        1
  •  1
  •   Rachel    10 年前

    没有理由在中找不到现有项 List<T> 使用上面的代码。

    当我注意到其中包含的输出值时,我应该在脑海中敲响警钟 Dictionary<int,int> 包含项目Id和 现有列表中项目的索引 .

    正在使用删除项目 existingRecords[existing[id]] 哪里 existing[id] 将返回项目的索引 existingRecords 。为了使其工作,必须从最大索引向下删除项目。如果较小的索引在较大的索引之前被删除,则较大的索引现在不正确1个位置,错误的项目被删除。

    至于为什么我会得到重复的项目,这是因为有两个集合正在维护,一个用于确定项目是否是新的/更新的/删除的,另一个则绑定在UI中显示。第一个集合更新不正确,而第二个集合没有更新,导致项目可能多次添加到UI集合中。

    我的短期解决方案是 removes 集合,以确保按每个项目的索引降序排序。我的长期解决方案是重写代码

        2
  •  0
  •   dorhanner    11 年前
    List.Contains(r) 
    

    将尝试在列表中找到a.Equals(r)的对象a。如果MyClass不覆盖Equals,则无法确定同一类的两个不同对象是否相等。 我对此不完全确定:但我认为equals使用GetHashCode(),如果您决定覆盖其中一个,则应该覆盖另一个。

    下面是MSDN: http://msdn.microsoft.com/en-us/library/bhkz42b3(v=vs.110).aspx