【问题标题】:Can the debugger tell me a count/status of a foreach loop?调试器可以告诉我 foreach 循环的计数/状态吗?
【发布时间】:2011-06-09 21:16:58
【问题描述】:

假设我有以下代码:

List<SomeObject> someObjects = ReturnListWithThousandsOfObjects();

foreach(SomeObject someobject in someObjects)
{
   DoSomething.With(someObject);
}

还假设在运行一分钟后我在DoSomething.With(someObject); 上设置了一个断点。

调试器对我来说很好。但现在我想知道我在列表迭代中处于什么位置(假设列表无序/没有键)。

有没有办法让调试器说“foreach 已经运行了 2321 次迭代中的 532 次”?

【问题讨论】:

标签: c# debugging foreach


【解决方案1】:

作为一种调试方法,没有 indexof 方法吗?

快速观察 - someObjects.indexOf(someObject);

已添加 - 有点简短抱歉。

正如 Guffa 所指出的,如果值是唯一的或默认相等比较器 EqualityComparer 函数使用唯一值(例如自定义 GetHashCode/Equals 重载),这将最有效。

    public class ATest
    {
        public int number { get; set; }
        public int boo { get; set; }
        public ATest()
        {

        }
    }

    protected void Go()
    {
        List<ATest> list = new List<ATest>();

        foreach(var i in Enumerable.Range(0,30)) {
            foreach(var j in Enumerable.Range(0,100)) {
                list.Add(new ATest() { number = i, boo = j });                  
            }
        }

        var o =0; //only for proving concept.
        foreach (ATest aTest in list)
        {               
            DoSomthing(aTest);
            //proof that this does work in this example.
            o++;
            System.Diagnostics.Debug.Assert(o == list.IndexOf(aTest));
        }

    }

【讨论】:

  • 只要集合中没有重复项,它就可以工作。如果是,它无法分辨出您正在查看的是哪一个匹配对象。
  • 取决于比较是根据什么进行的,如果它的哈希码可能是唯一的,嗯,也许我会收回这个声明。
  • @Mike Miller:我认为你应该添加它的限制。它在应用时仍然有用。
  • 这个似乎最有可能满足我的需求。 (我不想为一次性调试检查添加更多代码。这似乎让我(大部分时间)获得索引而不必更改我的代码)。谢谢!
  • 感谢您的接受,我确实认为 Andrei 给出的答案要好得多。
【解决方案2】:

这是针对 Visual Studio 的,但其他 IDE 应该也有类似的:

设置断点后,您可以右键单击它并转到“命中计数”。您可以在那里设置一些参数(“大于或等于” 0 将使其像常规断点一样工作 - “总是中断”)。有趣的部分是 Hit Count 字段(可以重置)。

这可以解决“迭代次数”部分。假设您使用的集合有这样一个现成可用的数字,恐怕您将不得不自己找到总数。

你也可以设置断点在大量点击后触发,比如几千/几百万(我不知道他们的限制是多少)。 然后,当“真正的”断点触发时,即您想知道原始断点被击中多少次的那个,您可以检查它并在需要时将其重置。

【讨论】:

  • 如果您想在预定数量的断点命中后停止,这很好,但不是在任意点。如果您总是在断点处中断,那么对于 1000 个项目继续单击继续会有点错误。
  • 必须是Hit Count &gt;= 1。将其设置为 0 无效(至少在 VS 2015 中)。
【解决方案3】:

这种情况,如果你真的想知道计数是多少,你不会使用for循环吗?

List<SomeObject> someObjects = ReturnListWithThousandsOfObjects();


for(int someObj= 1; someObj <= someObjects.Count; someObj++)
{
   Console.WriteLine(string.Format("{0} of {1} iterations", someObj, someObjects.Count));
   DoSomething.With(someObject[someObj]);
}

foreachfor 循环之间的性能没有真正的差异 - 因此,for 循环将是您想要实现的情况的更好选择。

【讨论】:

  • 为什么只为调试检查引入开销?
  • 有开销吗?这满足了他获得迭代计数输出的简报 - 无需停止调试器
  • 可能是我的解释,但他没有说明,'并且还假设在运行一分钟后我在 DoSomething.With(someObject); 上放置了一个断点。 - 似乎他想要一个一次性值而不是运行状态。
  • 哈哈,我的解释是不正确的——我收回了 :)
  • 我认为我能看到的唯一开销是 Console.WriteLine。这对于实现 OP 的要求并不是真正必要的。他只是想看看他正在进行哪个迭代,检查 someObj 和 someObjects.Count 的值会给他那个信息。在我看来,其余的都是正确的。 (编辑:我真的必须打字更快:))
【解决方案4】:

除非您手动将计数保存在变量中,否则您将无法轻松确定这一点。当循环在你的集合中迭代时,它只是使用枚举器来获取集合中的下一个元素,告诉它退出时没有更多元素了。

要手动保持计数,您只需这样做:

int count = 0;
List<SomeObject> someObjects = ReturnListWithThousandsOfObjects();

foreach(SomeObject someobject in someObjects)
{
     count++;
     DoSomething.With(someObject);
}

现在您可以随时暂停执行并查看您正在进行的迭代

【讨论】:

  • 我认为您回答问题的原因与 Stack72 相同
  • @Mike Miller 从我收集到的问题的最后一行,他想知道是否有一种简单的方法可以从调试器中获取“foreach 在 y 的迭代 x 中”。答案是没有,你必须自己跟踪。如果您打算在代码中保留计数变量,而不是在调试后将其删除,您可以使用预处理器指令将其从编译中排除在构建版本时。
【解决方案5】:

在 List 和 List 上创建一个扩展方法,它接受一个 Action 折叠、Action sideFold,它可以让您累积副作用,例如检查调试器的存在和中断累积状态。

【讨论】:

    【解决方案6】:

    是的,它可以。以下是 [在 VS 2017 中] 的方法:

    1. 在 foreach 循环内设置断点
    2. 右键单击断点并选择“操作”
    3. 在文本框中,输入以下内容:$FUNCTION {list.Items.IndexOf(item)} 其中“list”是您的列表名称,“item”是当前项目
    4. 继续运行代码并观察输出窗口

    【讨论】:

    • 投反对票,请解释为什么这个解决方案不起作用。
    猜你喜欢
    • 2011-10-30
    • 2016-10-11
    • 1970-01-01
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 2014-08-22
    • 2019-11-29
    • 1970-01-01
    相关资源
    最近更新 更多