37

Other than setting a debug variable and incrementing it every time you start the foreach, when you break in with the Visual Studio debugger connected, is there a way to tell that this is the Xth time through the loop?

I guess this would be a feature of Visual Studio if anything, not something that would be added to the compiled code.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Matt
  • 24,106
  • 61
  • 180
  • 291
  • 1
    It takes two seconds to convert a `foreach` to a `for` with an index. What's the big deal? – Josh Stodola Jul 20 '10 at 18:25
  • Would'nt it be any good if you wrote your reasons to upvote? I've never had any issue about breakpoints that i remember of. It has alotof feature, just right click over it. – Emrah GOZCU Jul 20 '10 at 18:33
  • possible duplicate of [(C#) Get index of current foreach iteration](http://stackoverflow.com/questions/43021/c-get-index-of-current-foreach-iteration) – Hans Passant Jul 20 '10 at 18:40
  • 6
    @Josh - It also takes 2 seconds to set a breakpoint with a hitcount. The Debugger is our friend, we need to learn how to use it. – kirk.burleson Jul 20 '10 at 18:50
  • 1
    @kirk And how many times are you going to waste two seconds before you realize that you should've used an index variable to begin with? – Josh Stodola Jul 20 '10 at 19:36
  • 6
    @Josh, are you actually suggesting that one categorically avoids the use of a `foreach` loop if *ever* they want to determine the index within the debugger? – Kirk Woll Apr 05 '11 at 16:32
  • 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:11
  • 2
    I might be already in the middle of a time-consuming run, in which case I would have to start again, which would take far more than 2 seconds. – Stewart May 22 '17 at 11:23
  • Furthermore, it seems to me that a breakpoint's hit counter increments only when the breakpoint is enabled. The only way I can find to make it count the iterations without stopping is to add a logging action to the breakpoint and then set it to continue execution. – Stewart May 22 '17 at 12:54

10 Answers10

23

Set a breakpoint inside the loop, then right click on the breakpoint to set the conditions. You can also right click to see the hit count while debugging and reset it if you want. You can set a boolean expression that is evaluated when the breakpoint hits to conditionally break (or just pass over).

Garo Yeriazarian
  • 2,493
  • 17
  • 29
  • Just tried this (VS 2015 Pro) and nope, it doesn't work. If the condition doesn't pass, this suppresses the increment of the hit count, not only the breaking. – Stewart May 22 '17 at 13:14
14

You can also use Visual Studio's Immediate Window, which allows you to write C# expressions against any variables in scope while debugging. Use the List.IndexOf() method, like so:

querying the foreach iteration index in the Immediate Window

Jeremy Deal
  • 308
  • 2
  • 8
  • Easy & simple !! – Greg Foote Aug 01 '19 at 17:10
  • Useful! When all objects are unique and in a List/array... Careful though, there may be duplicates, and maybe the foreach is over `list.Where(x => x != null)`. It's really an answer to "what is the first index of the current object" not "what is the index of the current iteration". – johv May 15 '21 at 13:29
13

Expanding on Garo Yeriazarian's answer...

A quick and dirty way without recompiling. Example code:

    var ints = new[] {5, 6, 0, 1};

    foreach (var i in ints)
    {
        Debug.WriteLine(100 / i);
    }

Add one breakpoint before the loop and one inside it. When the first is hit and you want to start counting, set a Hit Count condition:

two breakpoints

Set some large hit count condition and reset the counter and continue. Then when the exception or whatever fires, you can check the "Current hit count" again.

Hit count dialog

johv
  • 3,774
  • 3
  • 24
  • 38
9

Heres a previous Stack Overflow question that seems to be what your looking for: get-index-of-current-foreach-iteration

Answer quoted from that link:

Foreach is for iterating over collections that implement IEnumerable. It does this by calling GetEnumerator on the collection, which will return an Enumerator.

This Enumerator has a method and a property:

  • MoveNext()
  • Current

Current returns the object that Enumerator is currently on, MoveNext updates Current to the next object.

Obviously, the concept of an index is foreign to the concept of enumeration, and cannot be done.

Because of that, most collections are able to be traversed using an indexer and the for loop construct.

I greatly prefer using a for loop in this situation compared to tracking the index with a local variable.

Community
  • 1
  • 1
jumpdart
  • 1,664
  • 14
  • 31
5

May be you can use breakpoint hit count. Not exactly what you want, but may be helpful.

Also is there any serious reason why you don't want to use for loop in this case.

Incognito
  • 16,037
  • 9
  • 50
  • 72
  • 1. What's the point of having foreach if one can't use it? 2. It isn't clear whether the OP is trying to do it with an already-running program in order to determine how many times the loop has already iterated. This is the problem I was trying to solve - it is taking absolutely ages to run, and I wanted to see how many times it has run so far in order to estimate how much longer it will take. Stopping the program, changing the code and starting all over again is the last thing one wants to do in this scenario! – Stewart May 22 '17 at 13:22
4

Here's how I do it [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
4

Update Feb 2017, six years later - the extension mentioned below is now called OzCode. The feature is now called Foresee, but is only supported in VS2013.

I also felt that this could be a very useful feature, so I created it as part of a commercial extension I made for the Visual Studio debugging experience called BugAid.

The extension shows you exactly which iteration you are whenever you are inside a foreach loop: Foreach Buttons

When you click the "Iteration x of y" button, you'll see a new window, showing the complete list of items, with the your current location in the loop highlighted (this list is only shown if evaluating the collection in the debugger does not cause any side effects).

Once you open ths Foreach Visualization window, you can even right click any of the upcoming items and choose "Skip to Item", to run forward until you hit that item (this can save you from manually setting-up and messing with hit-count breakpoint):

Using Skip To Iteratioon

Omer Raviv
  • 10,717
  • 4
  • 40
  • 81
  • How have I never heard of this extension!!!???? If it performs as well as it looks it is absolutely going on my "To Buy" list! – Vaccano Nov 18 '11 at 21:20
  • Thank you :) You probably didn't hear about it because we just released these features yesterday ;). We are still in beta so please let us know about any problem you come across! – Omer Raviv Nov 18 '11 at 21:37
  • @OmerRaviv: Is the extension you refer to now named OzCode? You might want to update your old links, right now they're giving google juice to the nefarious website that took over the domain name. – Ben Voigt Feb 24 '17 at 16:08
  • @BenVoigt Thanks for the heads up! Updated. – Omer Raviv Feb 24 '17 at 22:01
3

Let's say your code is

foreach (String line in lines){
    Console.WriteLine(line);//breakpoint here
}

Put a breakpoint inside foreach loop, launch "Immediate window" and execute following code Array.IndexOf(lines, line);

user961954
  • 3,204
  • 2
  • 14
  • 24
  • 1
    This is the easiest solution working for arrays and without any code changes. You just have to take care that your list does not contain duplicates, then it wouldn't work (and always print you the first occurance). – Tobias Mar 20 '19 at 15:41
2

Have you tried using assertion in debugging? The debugger will be launched at that exact point in your code:
For example: System.Diagnostics.Debug.Assert (myValue >=0)

0

If whatever you are iterating supports the IndexOf() method, you don't have to set a debug variable.

Like in this example:

foreach (var i in myList)
{
    reportprogress(myList, i);

    //Do stuff
}

private void reportprogress<T>(List<T> l, T i)
{
    progressBar1.Value = ((l.IndexOf(i)) * 100) / l.Count;
    Application.DoEvents();
}
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Luiscencio
  • 3,697
  • 13
  • 41
  • 73