Почему цикл foreach только для чтения в С#
Почему цикл foreach является только для чтения? Я имею в виду, что вы можете получать данные, но не можете увеличивать ++ или уменьшать--. Любая причина этого?
Да, я новичок:)
Exmaple:
int[] myArray={1,2,3};
foreach (int num in myArray)
{
num+=1;
}
Ответы
Ответ 1
Это потому, что foreach предназначен для итерации по контейнеру, поэтому каждый элемент посещается ровно один раз, не меняя контейнер, чтобы избежать неприятных побочных эффектов.
Смотрите: foreach в MSDN
Если вы имели в виду, почему изменения элемента, такого как целое число, не влияют на контейнер целых чисел, это объясняется тем, что переменная итерации в этом случае будет типом значения и будет скопирована, например:
// Warning: Does not compile
foreach (int i in ints)
{
++i; // Would not change the int in ints
}
Даже если переменная итерации была ссылочным типом, чьи операции возвратили новый объект, вы не изменили бы исходную коллекцию, вы бы просто переназначали эту переменную большую часть времени:
// Warning: Does not compile
foreach (MyClass ob in objs)
{
ob=ob+ob; // Reassigning to local ob, not changing the one from the original
// collection of objs
}
В следующем примере есть возможность реально изменить объект в исходной коллекции, вызвав метод мутации:
// Warning: Does not compile
foreach (MyClass ob in objs)
{
ob.ChangeMe(); // This could modify the object in the original collection
}
Чтобы избежать путаницы в отношении значений по сравнению с ссылочными типами и сценариями, упомянутыми выше (наряду с некоторыми причинами, связанными с оптимизацией), MS решила сделать переменную итерации readonly
.
Ответ 2
Поскольку текущий элемент возвращается значением (то есть скопировано). И изменение копии бесполезно. Если это ссылочный тип, вы можете изменить содержимое этого объекта, но не можете заменить ссылку.
Возможно, вам стоит прочитать документацию IEnumerable<T>
и IEnumerator<T>
. Это должно стать более ясным. Самый важный бит состоит в том, что IEnumerable<T>
имеет свойство Current
типа T
. И это свойство имеет только геттер, но нет сеттера.
Но что произойдет, если у него есть сеттер?
- Это будет хорошо работать с массивами и списками
- Это не будет работать с сложными контейнерами, такими как хеш-таблицы, упорядоченный список, потому что изменение вызывает большие изменения в контейнере (например, переупорядочение) и, таким образом, делает недействительным итератор. (Большинство коллекций аннулируют итераторы, если они модифицируются, чтобы избежать несогласованного состояния в итераторах.)
- В LINQ это не имеет никакого смысла. Например, с помощью
select(x=>f(x))
значения являются результатами функции и не связаны с постоянным хранением.
- С итераторами, написанными синтаксисом
yield return
, это не имеет смысла либо
Ответ 3
foreach
предназначен для посещения каждого элемента в коллекции ровно один раз и не использует явный "индекс цикла"; если вы хотите больше контролировать цикл и иметь индекс цикла, используйте for
.
РЕДАКТИРОВАТЬ: вы можете изменить элементы в коллекции, которые повторяются внутри цикла foreach
. Например:
foreach(Chair ch in mychairs)
{
ch.PaintColour = Colour.Green; //this alters the chair object *in* the collection.
}
Однако вы не можете добавлять или удалять элементы в/из коллекции.