Подтвердить что ты не робот

Почему цикл foreach только для чтения в С#

Почему цикл foreach является только для чтения? Я имею в виду, что вы можете получать данные, но не можете увеличивать ++ или уменьшать--. Любая причина этого? Да, я новичок:)

Exmaple:

int[] myArray={1,2,3};
foreach (int num in myArray)
{
  num+=1;
}
4b9b3361

Ответ 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.
}

Однако вы не можете добавлять или удалять элементы в/из коллекции.