【问题标题】:C# code is hanging on a call to Listview.CheckedTems.Count - how to troubleshoot?C# 代码在调用 Listview.CheckediTems.Count 时挂起 - 如何排除故障?
【发布时间】:2017-08-30 22:43:53
【问题描述】:

我编写了一个在 Visual Studio 2017 中创建的 C# Windows 窗体。

在按钮单击事件处理程序中,我有一个永远不会完成的简单 if 语句:

if (listViewAddedKeys.CheckedItems.Count

listViewAddedKeys 是 ListView,“added”是 Hashtable。

这是完整的功能:

private void buttonSaveAdded_Click(object sender, System.EventArgs e)
    {
        try
        {
            saveFileDialog.ShowDialog();
            if (saveFileDialog.FileName != String.Empty)
            {
                OnProgressEvent("Saving Data...");
                DisableControls(this.Controls);
                if (listViewAddedKeys.CheckedItems.Count < added.Count)
                    HashFromSelected(ref listViewAddedKeys, ref added, out currentSaving, false);
                else
                    currentSaving = added;
                BeginSaveData.BeginInvoke(saveFileDialog.FileName, ref currentSaving,
                    OnSaveDataCallback, BeginSaveData);
            }
        }
        catch (Exception ex)
        {
            OnProgressEvent("Problem in buttonSaveAdded_Click(): " + ex.Message);
        }
    }

listViewAddedKeys 是 ListView,“added”是 Hashtable。

如果我断线: DisableControls(this.Controls);

并将“listViewAddedKeys.CheckedItems.Count”添加到调试器的“Watch 1”选项卡中,调试器无法检索该值(函数评估超时)。如果我将其更改为“listViewAddedKeys”,我可以深入了解它(例如,我可以看到项目数为 1,478,670),但是,如果我继续向下滚动它,Visual Studio 会崩溃.

我没有对线程做任何棘手的事情,我对任何东西的唯一锁定设置了一个尚未触发的断点。

我尝试按照 here 的建议进行操作,但 windbg 中的输出与他们希望我查找的项目都不匹配。

此时运行时 CPU 利用率为 0,资源管理器显示它没有对磁盘、内存或网络做任何事情。

这是在 Windows 10(截至 2017 年 8 月 30 日已完全修补)企业系统上。该代码是为 .NET Framework 4.6.1 编译的。代码分析干净利落。

在声明问题不在于我的代码之前,我还可以执行任何其他步骤吗?

【问题讨论】:

  • 只在调试时遇到这个问题?如果你不调试就运行它可以正常工作吗?
  • 当我在调试器之外执行时也会出现问题。

标签: c# wpf listview visual-studio-2017


【解决方案1】:

首先,如果问题不在您的代码中,您仍然需要学习足够的知识来创建解决方法,对吧?

您可以采取的一些调试步骤:

  1. 为计数创建临时变量,看看是否可以在 if 语句之外跳过它们:
int tmpListViewCount = listViewAddedKeys.CheckedItems.Count;
int tmpAddedCount = added.Count;
if( tmpListViewCount < tmpAddedCount )
{ // HashFromSelected, etc.. }
  1. 交换tmpListViewCounttmpAddedCount或使用其他方法先运行tmpAddedCount

  2. 尝试实例化一个 .CheckedItems 列表或从listViewAddedKeys 中提取它,使其成为一个单独的对象。有没有一种方法可以直接检查它,以便知道其中有多少对象(即计数应该返回什么)?也许通过断点和鼠标悬停?直接在该对象上尝试.count。也许创建一个静态的,您可以直接将列表设置为(不确定该类是什么)。

CheckedItemsClass tmpCheckedItems = listViewAddedKeys.CheckItems; 
int tmpListViewCount = tmpCheckedItems.Count;
int tmpAddedCount = added.Count;
if( tmpListViewCount < tmpAddedCount )
{ // HashFromSelected, etc.. }    
  1. 设置 UI,以便您使用静态 listViewAddedKeys.CheckedItemsadded 变量调用此函数,这些变量具有您提前知道的已定义计数(1 会很好...)。也许可以组成一个按钮,每个按钮添加 1 个项目,然后调用此函数,如果成功,您可以手动添加更多。

我感觉问题在于“CheckedItems”正在创建什么或如何计算,但不确定。当您计算 Checked Items 时,是否会增加计数,形成无限循环?无论如何,这些至少应该显示一些调试方法,您可以使用它们来分解和设置调试会话,以便您可以更好地控制情况。理想情况下,您在调试之前提前知道您期望这两个计数是什么 - 假设您期望这些方法如何工作以及它们将返回什么,然后您可以明确了解哪些事情不符合您的期望。之后准确地修改你发送到函数中的内容,看看它如何改变响应等。基本上,应用科学的方法。

【讨论】:

  • int tempCount = listViewAddedKeys.CheckedItems.Count;永远不会回来。最终,调试器指出已引发异常:“托管调试助手 'ContextSwitchDeadlock' 检测到...中的问题:CLR 无法从 COM 上下文 0x10dcd18 转换到 COM 上下文 0x10dcc60 60 秒。拥有的线程目标上下文/单元很可能是在执行非泵送等待或处理非常长时间运行的操作而不泵送 Windows 消息。”
  • ... " 这种情况通常会对性能产生负面影响,甚至可能导致应用程序变得无响应或内存使用量随时间不断累积。为避免此问题,所有单线程单元 (STA)线程应该使用泵送等待原语(例如 CoWaitForMultipleHandles)并在长时间运行的操作期间定期泵送消息。”
  • 所以你找到了你需要深入挖掘的兔子洞(即我列表中#1和#2的目标)。 #3 和 #4 怎么样?
  • 对于#3,我在 OP 中提到,如果我尝试调查该对象,Visual Studio 会崩溃。我也试过这个: ListView.CheckedListViewItemCollection temp = listViewAddedKeys.CheckedITems;如果我尝试获取 temp 的计数,它也会失败。计数应该是 1,478,670——奇怪的是,我可以得到列表视图中所有项目的计数,只是当我检查 Checked 项目时才会发生这种情况。换句话说,没有兔子洞可挖。问题似乎出在 .net 代码本身。
  • 显然可以进入.net 的源代码——我不知道这一点。 How to: Debug .NET Framework Source我去看看到底是什么地方出了问题。
猜你喜欢
  • 2010-10-13
  • 1970-01-01
  • 2012-12-07
  • 1970-01-01
  • 2017-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多