协慌网

登录 贡献 社区

你如何获得 foreach 循环的当前迭代的索引?

是否有一些罕见的语言构造我没有遇到过(比如我最近学到的一些,有些是关于 Stack Overflow)在 C#中得到一个表示 foreach 循环当前迭代的值?

例如,我目前根据具体情况做这样的事情:

int i = 0;
foreach (Object o in collection)
{
    // ...
    i++;
}

答案

Ian Mercer 在Phil Haack 的博客上发布了类似的解决方案:

foreach (var item in Model.Select((value, i) => new { i, value }))
{
    var value = item.value;
    var index = item.i;
}

这将通过使用Linq 的Select这个重载来获取 item( item.value )及其索引( item.i ):

函数 [select Select] 的第二个参数表示源元素的索引。

new { i, value }正在创建一个新的匿名对象

如果您使用的是 C#7.0 或更高版本,则可以使用ValueTuple来避免堆分配:

foreach (var item in Model.Select((value, i) => ( value, i )))
{
    var value = item.value;
    var index = item.i;
}

您也可以删除该item.通过使用自动解构:

<ol>
foreach ((MyType value, Int32 i) in Model.Select((value, i) => ( value, i )))
{
    <li id="item_@i">@value</li>
}
</ol>

foreach用于迭代实现IEnumerable集合。它通过在集合上调用GetEnumerator来执行此操作,该集合将返回Enumerator

此枚举器有一个方法和属性:

  • 的 MoveNext()
  • 当前

Current返回 Enumerator Current的对象, MoveNext Current更新为下一个对象。

索引的概念对于枚举的概念是陌生的,并且不能完成。

因此,大多数集合都可以使用索引器和 for 循环结构遍历。

与使用局部变量跟踪索引相比,我更倾向于在这种情况下使用 for 循环。

可以做这样的事情:

public static class ForEachExtensions
{
    public static void ForEachWithIndex<T>(this IEnumerable<T> enumerable, Action<T, int> handler)
    {
        int idx = 0;
        foreach (T item in enumerable)
            handler(item, idx++);
    }
}

public class Example
{
    public static void Main()
    {
        string[] values = new[] { "foo", "bar", "baz" };

        values.ForEachWithIndex((item, idx) => Console.WriteLine("{0}: {1}", idx, item));
    }
}