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

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

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

当前回答

这样你就可以使用LINQ来使用索引和值:

ListValues.Select((x, i) => new { Value = x, Index = i }).ToList().ForEach(element =>
{
    // element.Index
    // element.Value
});

其他回答

除非你的集合可以通过某种方法返回对象的索引,否则唯一的方法就是使用像你的例子中那样的计数器。

然而,当使用索引时,唯一合理的答案是使用for循环。其他任何事情都会带来代码的复杂性,更不用说时间和空间的复杂性了。

只需添加自己的索引。保持简单。

int i = -1;
foreach (var item in Collection)
{
    ++i;
    item.index = i;
}

foreach用于迭代实现IEnumerable的集合。它通过在集合上调用GetEnumerator来实现这一点,该集合将返回一个Enumerator。

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

MoveNext () 当前的

Current返回Enumerator当前所在的对象,MoveNext将Current更新为下一个对象。

索引的概念与枚举的概念是不同的,不能这样做。

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

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

使用计数器变量并没有什么错。事实上,无论使用for、foreach while还是do,计数器变量都必须在某处声明并递增。

所以,如果你不确定你是否有一个适当索引的集合,请使用这个习语:

var i = 0;
foreach (var e in collection) {
   // Do stuff with 'e' and 'i'
   i++;
}

否则,如果你知道你的可索引集合是O(1)索引访问(它将是数组和可能List<T>(文档没有说),但不一定对其他类型(如LinkedList)):

// Hope the JIT compiler optimises read of the 'Count' property!
for (var i = 0; i < collection.Count; i++) {
   var e = collection[i];
   // Do stuff with 'e' and 'i'
}

它应该永远不需要通过调用MoveNext()和询问Current来“手动”操作IEnumerator - foreach是为你省去了那个特别的麻烦…如果您需要跳过项目,只需在循环体中使用continue。

为了完整起见,根据你对索引的处理(上面的结构提供了足够的灵活性),你可以使用Parallel LINQ:

// First, filter 'e' based on 'i',
// then apply an action to remaining 'e'
collection
    .AsParallel()
    .Where((e,i) => /* filter with e,i */)
    .ForAll(e => { /* use e, but don't modify it */ });

// Using 'e' and 'i', produce a new collection,
// where each element incorporates 'i'
collection
    .AsParallel()
    .Select((e, i) => new MyWrapper(e, i));

我们使用上面的AsParallel(),因为现在已经是2014年了,我们希望充分利用这些多核来加快速度。此外,对于“顺序”LINQ,你只能在List<T>和Array…上获得ForEach()扩展方法。而且不清楚使用它是否比简单的foreach更好,因为您仍然在运行单线程的更难看的语法。

像这样的怎么样?注意,如果myEnumerable为空,myDelimitedString可能为空。

IEnumerator enumerator = myEnumerable.GetEnumerator();
string myDelimitedString;
string current = null;

if( enumerator.MoveNext() )
    current = (string)enumerator.Current;

while( null != current)
{
    current = (string)enumerator.Current; }

    myDelimitedString += current;

    if( enumerator.MoveNext() )
        myDelimitedString += DELIMITER;
    else
        break;
}