【问题标题】:Breakpoint that breaks when data changes in a managed language当托管语言中的数据更改时中断的断点
【发布时间】:2010-09-28 17:00:46
【问题描述】:

我有一个带有列表属性的类,在某些情况下它似乎丢失了一个元素。我不知道什么时候会发生这种情况。

所以我想做的是设置一个 Visual Studio 断点,该断点将在此值更改时暂停程序。条件断点在这种情况下不起作用,因为我不知道是什么删除了这个断点。

换句话说,我希望我的程序在 myList.Count 计算为新数字的那一刻停止。

关于如何做到这一点的任何想法?

【问题讨论】:

    标签: c# debugging breakpoints


    【解决方案1】:

    由于 CLR 限制,这在 C# 或任何其他 .NET 语言中是不可能的。 Visual Studio 本机代码调试器支持 C++ 代码的数据断点 (link),它们正是这样做的,但托管代码不支持。您可以尝试中断或拦截集合上的 AddRemove 方法调用,如该问题的其他答案中所建议的那样。

    【讨论】:

    • 托管代码 ~= CLR/Microsoft 中间语言
    • 谢谢。 “~=”是什么意思?它的右手边是它左手边的准确定义吗?如果不是,你能给出一个准确的定义吗?
    • "~=" 在此上下文中表示“大约等于”。
    • 谢谢。它的一般定义是什么,而不是在这种情况下?
    • 现在可以在 VS2019 中使用,但仅适用于 .Net Core 3.0 及更高版本。请参阅 VS2019 的另一个答案。
    【解决方案2】:

    List<T> 换成ObservableCollection<T> 并监听CollectionChanged 事件怎么样?它实现了IList<T> 接口,因此可用方法应该有足够的重叠,以实现语法和语义兼容性。

    【讨论】:

    • 这是个好主意!我不敢相信我之前没想过使用 ObservableCollection。调用 CollectionChange 时,有没有办法将堆栈追溯到进行更改的代码行?
    • @Jason:是的,我想是的。由于事件是同步引发的,因此启动更改的代码应该出现在调用堆栈中的某个地方吗?
    • 对我来说很有意义。下次遇到类似情况时我会试试这个。谢谢!
    【解决方案3】:

    现在可以在 Visual Studio 2019 中实现。 在此处查看发行说明:https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes

    本文使用 Preview 2 进行了一些详细介绍。 https://devblogs.microsoft.com/visualstudio/break-when-value-changes-data-breakpoints-for-net-core-in-visual-studio-2019/

    请注意,这仅适用于 .NET Core,而不适用于即将成为旧版的成熟的仅适用于 Windows 的 .NET 框架。

    【讨论】:

    • 有趣,但该功能似乎仅适用于 .NET Core。
    • 此微软博客指出数据断点功能仅适用于 .Net Core 3.0 及更高版本中的托管代码:devblogs.microsoft.com/visualstudio/…
    【解决方案4】:

    我假设 Visual Studio 是 IDE。

    设置断点,右键单击它,选择条件,键入 myList.Count,然后选择 Has Changed。

    【讨论】:

    • “条件断点在这种情况下不起作用,因为我不知道是什么删除了这个断点。”
    • 但这会停止执行,您可以检查调用堆栈中的违规者。 :)
    • 但是会的;在这种情况下,我必须知道在哪里设置断点。我认为条件断点很棒并且一直都在使用它们,但是在我写这个问题时的这种情况下,我不知道是哪一行代码导致了这个问题。不过,我很欣赏你对这个问题的想法。谢谢!
    【解决方案5】:

    子类列表 使用您自己的类,然后覆盖 Count(或添加/删除)并在您创建的方法中添加断点。

    编辑:正如 cmets 中提到的,这将需要大量的努力,因为 Add 和 Remove 方法不是虚拟的;需要对方法进行完全重写。

    此外,子类化 Collection 显然是一个更好的解决方案(尽管我无法辨别为什么 Add/Remove 也不是 Collection 的虚拟成员;cmets?)。

    【讨论】:

    • 您不能覆盖添加/删除方法,因为它们不是虚拟的。您可以隐藏此方法并提供新版本,但在这种情况下,您应该将所有用法从 List 更改为 MyList
    • 如果您将List<T> 替换为Collection<T>,这将更加可行。
    【解决方案6】:

    您可以在 Visual Studio 中设置数据断点,但这对于托管代码来说很难做到,因为垃圾收集器可能会移动对象。也就是说,您仍然可以将其拉下来。您必须为您的进程启用本机调试。在即时窗口中加载 SOS 并使用 !DumpObject 查找 Count 属性的后备存储地址。使用此地址,使用此地址创建一个新的数据断点,然后继续并触发问题。

    【讨论】:

    • 我从来没有尝试过这个,因为它与调试有关,但是你能不能不固定对象以防止 GC 移动它?
    【解决方案7】:

    查找此特定属性的所有用法,并将断点添加到从该列表中删除元素的所有行。

    或者您可以创建自己的 IList 实现并将断点设置为 Remove 方法(您不能在不更改所有客户端的情况下将 List 子类化,因为 List::Remove 不是虚拟的)。

    【讨论】:

    • 我接受了“查找所有用法”的建议。我希望有一个更简单的解决方案,但我理解为什么在 Visual Studio 中不可能。
    【解决方案8】:

    这可能更像是一个问题而不是一个答案,但您可以在调试时进入框架代码,前提是您以这种方式设置您的 Visual Studio。然后您可以将断点放入实际的 List 实现中。

    【讨论】:

      【解决方案9】:

      这听起来可能太离谱或复杂,但您可以使用计时器/后台线程来继续测试计数值,并在发现值与之前的实例不同时执行Debugger.Break()

      【讨论】:

      • 一个有趣的想法,然而;它不会给我我正在寻找的结果。我想知道导致更改的确切行。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-12
      • 1970-01-01
      • 1970-01-01
      • 2021-04-18
      相关资源
      最近更新 更多