C# Feature Request – index available within foreach

dom (at least I think it's 'dom' - he's made a fair effort not to have his name anywhere on his blog page) asks for a language feature, and I respond


Comments (11)
  1. Eric TF Bat says:

    I’m a language junkie, so I’ll throw in some "prior art":

    Javascript has a foreach-ish statement, which inexplicably gives you the _index_, not the value, each time through the loop. Mildly irritating when you forget.

    Perl uses the syntax "foreach $var (@list)", which sets $var to each value in @list in order. Nothing there to handle the ordinal index, and I admit there are times I’ve missed it.

    XSLT has an xsl:for-each element that maintains an internal function called position(). You can do something very much like [xsl:if test="position()=1"] or [xsl:if test="position()=last()"] inside the loop, and it works as you’d expect. When you’re converting from XML to HTML with CSS, this is frequently useful! (Excuse the square brackets; without a preview button I can’t tell what will happen to angle brackets until it’s too late.)

    PHP has the best syntax: "foreach ($list as $value)" or "foreach ($list as $index=>$value)" – this works with associative arrays (aka dictionaries, hashes, string-indexed arrays, or whatever you want to call them) and with ordinary integer-indexed arrays.

    The C# analog to the PHP syntax would look like "foreach (int i:object val in myarray)" and wouldn’t, as far as I can tell, break any code. Whether it would break other things (efficiency, compiler integrity, the brains of the implementers, etc) is not for me to say.

  2. Shawn says:

    I like "Dom"’s suggestion after Erics reply where "foreach" has another meaning inside a for loop…


    foreach(int x in myarray) {

    if (foreach.first) {


    if (foreach.last) {


    if (foreach.index == 49) {



    The only "potential" problem I see with this is that for each can’t be nested, unless the compiler is smart enough to pick up on the context of its use.



  3. William says:

    I am going to continue with Shawn.

    //object that has the first, last, current(index)

    feObject FE = new feObject();

    foreach( int x in myarray, FE ) {

    if ( FE.index == 0 )

    //first record;

    if ( FE.Count == FE.index + 1 )

    //last record;


    They could be safely nested this way, without breaking any code. I,however, do not understand what the compiler does when finding a foreach loop…

  4. Eric TF Bat says:

    If I know Anders (I don’t, other than through his earlier work) there won’t be any change to "his" language that isn’t simple, elegant and Just Plain Right. I fully expect the other people on the team would be in agreement. The issues that I can foresee include:

    1. Referring to the index of outer-nested foreach loops: it’s interesting that XSLT, with its position() function, doesn’t give you a way to do this, beyond saving position in an xsl:variable outside the inner loop. In fact, I’ve rarely needed this, and I think it would be mad to discard the whole feature just for this.

    2. Dealing with _unordered_ arrays, aka dictionaries or associative arrays – ones that, like Perl’s hashes, have no fixed order to their elements and will give the elements to a foreach function in some arbitrary way that you know not to rely on if you don’t apply a sort function; what happens if you say "foreach (int i : object ob in array)" and there is no sensible index value for each object?

    3. Dealing with associative arrays where you’d really like the index AND the key AND the value; should it be "foreach (int i : string name : object data in persondata)"???

    My head hurts.

  5. Gavin Greig says:

    (I know C# doesn’t have templates but) …wouldn’t this be a good candidate for implementation as a template with a policy parameter which determined whether you use the more efficient default foreach or the less-efficient-but-useful indexed foreach?

    I understand that managed C++ is going to have both templates and generics – is there any consideration of adopting templates into C#?

    I don’t have a strong opinion as to whether that would be desirable or not, just curious as to whether it’s been considered.

  6. Diego Mijelshon says:

    Although it’s only syntactic sugar, it would be really nice to have foreach wrap also IDictionaryEnumerator, like PHP (The only problem is that we would have to implement IDictionaryEnumerable…)

    Something like:

    foreach (string key, Control value in MyControlCollection) {…}

  7. Eric says:

    templates – it’s very unlikely we’d add templates to C#. Generics covers the important scenarios now…

  8. I find myself missing an indexer mostly when I need to walk through two or more collections in parallel. So it would more valuable to me if foreach was extended to support that. For example, instead of writing this:

    int index = 0;

    foreach(string key in keysCollection)


    string value = valuesCollection[I];


    I’d write this:

    foreach(string key in keysCollection, string value in valuesCollection)



    It’s somewhat similar to what regular “for” allows us to do:

    For(int i = 0, int j = 0; (i < icount) && (j < jcount); i++, j++)

    Of course, there are some other reasons for having an indexer. But I would not agree with dom or other people asking for access to an "extended" IEnumerator. Because… because I don’t think IEnumerator should be extended in first place. The whole idea behind IEnumerable and IEnumerator, as I understand it, is to abstract from an order or number of elements in the collection being enumerated. So perhaps the most elegant solution, if still needed, could be achieved though extending the language. It can be done through a number of ways and which one is picked is not that important really. Here’s just a couple of scenarios that I’d prefer:

    foreach(object o in collection)


    int i = stepnum(o);


    foreach(object o in collection, stepnum int i)



    where stepnum is a keyword.

    Whith all my respect, Eric, I don’t think that having one more implicit variable in the language is a good idea. I could explain why I don’t like it, but that’s probably a subject for a different discussion.

    PS.. Ah, language design.. must be a dream job…

  9. Ian Bicking says:

    OK, I might be foolish in this, since I don’t really know C#. But the way I’d do it in Python would be to define an decorating enumerator. This would keep track of the index, whether it was the first or last enumeration (figuring out if it’s the last requires a buffer, but that’s okay), and whatever else. Then the enumerator would produce (repeater, obj) objects — a tuple/pair of objects. The "repeater" object would have member variables with the index, etc., and obj would be the normal object. All of this part doable in C#, and shouldn’t require language extensions.

    It’s perhaps more convenient in Python, because you can unpack the tuple as part of the "for" (C#’s "foreach") statement. In C# it might look like:

    foreach ((repeater r, object o) in RepeatTracker(collection)) {…}

    It’s more annoying if you have to unpack the two variables yourself, which I suspect you must do in C#. But I don’t really know…

  10. Bill Trowbridge says:

    I see this as wanting particular side-effects that happen for each iteration. The question is: What syntax would provide those side-effects, and yet be simpler than the code needed to write it today?

    The Python-style unpacking is cool, but that won’t happen unless the language is changed throughout to support tuples. I think that would be nice for many reasons. More dynamic support for tuples and arrays would be very welcome.

    I agree with Val the the indexer need not necessarily be associated with the collection that is being enumerated. Often we need the index for other purposes.

  11. Yingle Jia says:

    I think we can enhance the foreach statement that take a index vaiable.

    For example I would like to write:

    foreach (Contact item [int i] in theContacts)

    Here [int i] is the item’s foreach index (of course, the index is optional). C# users should feel easy to understand and use it.

Comments are closed.

Skip to main content