Não há nada errado em usar uma variável de contador. De fato, se você usa for
, foreach
while
ou do
, uma variável de contador deve em algum lugar ser declarada e incrementada.
Portanto, use esse idioma se não tiver certeza se possui uma coleção indexada adequadamente:
var i = 0;
foreach (var e in collection) {
// Do stuff with 'e' and 'i'
i++;
}
Caso contrário, use este caso você saiba que sua coleção indexável é O (1) para acesso ao índice (para o qual será Array
e provavelmente List<T>
(a documentação não diz), mas não necessariamente para outros tipos (como 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'
}
Nunca deve ser necessário operar 'manualmente' IEnumerator
, invocando MoveNext()
e interrogando Current
- foreach
está poupando esse incômodo em particular ... se você precisar pular itens, basta usar um continue
no corpo do loop.
E, para ser completo, dependendo do que você estava fazendo com o seu índice (as construções acima oferecem bastante flexibilidade), você pode usar o 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));
Usamos AsParallel()
acima, porque já estamos em 2014 e queremos fazer bom uso desses múltiplos núcleos para acelerar as coisas. Além disso, para o LINQ 'sequencial', você sóForEach()
List<T>
Array
usa um método de extensão e ... e não está claro que usá-lo seja melhor do que fazer um simples foreach
, pois você ainda está executando o thread único para obter uma sintaxe mais feia.