8

Suppose I have the following code:

List<SomeObject> someObjects = ReturnListWithThousandsOfObjects();

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

And also suppose that after a minute of running I put a breakpoint on DoSomething.With(someObject);.

The debugger breaks for me just fine. But now I want to know what point am I at in my iteration of the list (assume the list is unordered/has no key).

Is there a way for the debugger to say "the foreach has run 532 of 2321 iterations"?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Vaccano
  • 70,257
  • 127
  • 405
  • 747
  • This question is very similar to [this one](http://stackoverflow.com/questions/3293051/debugging-a-foreach-loop-in-c-what-iteration-is-this), please see [my answer there](http://stackoverflow.com/questions/3293051/debugging-a-foreach-loop-in-c-what-iteration-is-this/8174760#8174760) – Omer Raviv Nov 17 '11 at 21:50
  • The canonical question is *[How do you get the index of the current iteration of a foreach loop?](http://stackoverflow.com/questions/43021)* (but there could be additional debugger tricks). – Peter Mortensen Jul 28 '15 at 12:09

6 Answers6

9

As a debugging one off isn't there an indexof method?

i.e.

quickwatch - someObjects.indexOf(someObject);

Added - Sorry if a bit brief.

As pointed out by Guffa this will work best if the values are unique or the default equality comparer EqualityComparer function uses a unique value (such as a custom GetHashCode/Equals overload).

    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
  • 15,200
  • 1
  • 17
  • 27
  • 1
    That would work as long as there are no duplicates in the collection. If it is, it can't tell which one of the matching objects you are looking at. – Guffa Jun 09 '11 at 21:31
  • depends what the comparison is done on, if its hashcode it could be unique, mmm maybe i'll retract this statement. – Mike Miller Jun 09 '11 at 21:33
  • 2
    @Mike Miller: I think that you just should add it's limitations. It can still be useful when it applies. – Guffa Jun 09 '11 at 21:41
  • This one seems the most likely to work for what I want. (I don't want to add more code for a one-off debug check. This seems to let me get the index (most of the time) and not have to change my code). THANKS! – Vaccano Jun 10 '11 at 15:55
  • Thanks for accepting, I do think the answer given by Andrei is far better though. – Mike Miller Jun 10 '11 at 16:41
  • I upvoted Andrei's answer, but yours fit what I was looking for better. – Vaccano Jun 24 '11 at 15:54
  • The IndexOf() method works for me. It was very helpful for a simple scenario. – Jerameel Resco Nov 21 '16 at 05:32
5

This is for Visual Studio, but other IDEs should have something similar:

When you set a breakpoint you can right-click it and go to "Hit Count". You can setup some parameters there ("greater than or equal to " 0 will make it work like a regular breakpoint - so would "break always"). The interesting part is the Hit Count field (which can be reset).

This can solve the "number of iterations" part. For the total number I'm afraid you're going to have to find it yourself, assuming the collection you use has such a number readily available.

You can also set the breakpoint to fire after a very large number of hits, say a few thousands/millions (I don't know what is their limit). Then, when the "real" breakpoint fires, the one where you want to know how many times the original breakpoint was hit, you can just examine it and reset it if needed.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Andrei
  • 4,592
  • 22
  • 28
  • This is fine if you want to stop after a pre-determined amount of hits to the breakpoint, but not at an arbitrary point. If you always break at the breakpoint it would be a bit erroneous to keep having to click continue for a 1000 items. – Mike Miller Jun 10 '11 at 07:56
  • It needs to be `Hit Count >= 1`. Setting it to 0 is invalid (at least in VS 2015). – Zoot Mar 17 '16 at 14:45
2

Is this case, if you really wanted to know what the count is, wouldn't you use a for loop?

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]);
}

There will be no real difference in performance between the foreach and the for loops - therefore the for loop will be a better alternative for the situation you want to achieve.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
stack72
  • 7,930
  • 1
  • 29
  • 34
  • Why introduce the overhead just for debugging inspection? – Mike Miller Jun 09 '11 at 21:28
  • Is there an overhead? this fulfils the brief where he gets an output of the iteration count - without needed to stop the debugger – stack72 Jun 09 '11 at 21:30
  • 1
    Might be my interpretation but he doesn't state that, 'And also suppose that after a minute of running I put a breakpoint on DoSomething.With(someObject);.' - seems he wants a one-off value not a running status. – Mike Miller Jun 09 '11 at 21:32
  • haha its my interpretation that is incorrect - I take that back :) – stack72 Jun 09 '11 at 21:35
  • I think the only overhead I can see is the Console.WriteLine. This isn't really necessary to achieve what the OP requested. He just wants to see which iteration he's on, inspecting the value of someObj and someObjects.Count will give him that info. The rest of it is spot on in my opinion. (Edit: I really must type faster :) ) – KazR Jun 09 '11 at 21:37
  • -1 you also don't populate someObject or declare it :) obviously i'll upvote when fixed. – Mike Miller Jun 09 '11 at 21:38
  • Fixed - was due to copy and paste - tried to answer far too quickly initially by the looks of that :( – stack72 Jun 09 '11 at 22:03
  • @Mike Miller - no need to apologise at all :) – stack72 Jun 10 '11 at 09:24
1

Unless you manually keep count in a variable you won't be able to easily determine this. As the loop is iterating across your collection it just uses the enumerator to grab the next element in the collection tell there are no more elements at which point it exits.

To manually keep a count you would just do:

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

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

Now at any point you can pause execution and see which iteration you are on

Clayton
  • 5,130
  • 1
  • 16
  • 15
  • I don't think you answer the question for the same reason as given to Stack72 – Mike Miller Jun 09 '11 at 22:17
  • @Mike Miller From the last line of the question I gathered that he wanted to know if there was an easy way to get from the debugger "the foreach is in iteration x of y". The answer is there is not, and you have to track this yourself. If you were going to leave the counting variable in your code and not just remove it after debugging, you could use preprocessor directives to have it excluded from compilation when building in release. – Clayton Jun 09 '11 at 23:50
0

Create an extension method on List and List which accepts a Action fold, Action sideFold that let's you accumulate side effects like checking for the existence of a debugger and breaking on accumulated state.

John Zabroski
  • 1,878
  • 2
  • 22
  • 46
-1

Yes it can. Here's how [in VS 2017] :

  1. Set a break point inside the foreach loop
  2. Right click the break point and select 'Actions'
  3. In the text box, enter the following: $FUNCTION {list.Items.IndexOf(item)} where 'list' is the name of your list and 'item' is the current item
  4. Continue running the code and watch the output window
brandonstrong
  • 530
  • 6
  • 20