Немає нічого поганого у використанні лічильної змінної. Насправді, чи ви використовуєте for
, foreach
while
чи do
змінну лічильника треба десь оголошувати та збільшувати.
Тож використовуйте цю ідіому, якщо ви не впевнені, чи маєте колекцію, відповідну індексуванню:
var i = 0;
foreach (var e in collection) {
// Do stuff with 'e' and 'i'
i++;
}
Інакше використовуйте цей, якщо ви знаєте, що ваша колекція, що підлягає індексуванню, є O (1) для доступу до індексу (що це буде Array
і, ймовірно, для 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'
}
Ніколи не слід «керувати рукою» за IEnumerator
допомогою виклику MoveNext()
та допиту Current
- 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 ви отримуєте лише ForEach()
метод розширення List<T>
іArray
... і не зрозуміло, що використовувати його краще, ніж робити простий foreach
, оскільки ви все ще працюєте з однопотоковою для синішого синтаксису.