Почему цикл foreach только для чтения в C # - PullRequest
13 голосов
/ 23 октября 2010

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

Exmaple:

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

Ответы [ 3 ]

10 голосов
/ 23 октября 2010

Это потому, что 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.

9 голосов
/ 23 октября 2010

Потому что текущий элемент возвращается по значению (т.е. копируется). И изменение копии бесполезно. Если это ссылочный тип, вы можете изменить содержимое этого объекта, но не можете заменить ссылку.

Возможно, вам следует прочитать документацию IEnumerable<T> и IEnumerator<T>. Это должно прояснить ситуацию. Наиболее важным битом является то, что IEnumerable<T> имеет свойство Current типа T. И это свойство имеет только геттер, но не сеттер.

Но что случилось бы, если бы у него был сеттер?

  • Хорошо бы с массивами и списками
  • Это не будет хорошо работать со сложными контейнерами, такими как хеш-таблицы, упорядоченный список, потому что изменение вызывает большие изменения в контейнере (например, переупорядочение) и, таким образом, делает недействительным итератор. (Большинство коллекций лишают законной силы итераторы, если они модифицируются, чтобы избежать противоречивого состояния в итераторах.)
  • В LINQ это вообще не имеет смысла. Например, с select(x=>f(x)) значения являются результатами функции и не имеют постоянного хранилища.
  • С итераторами, написанными с синтаксисом yield return, это тоже не имеет смысла
1 голос
/ 23 октября 2010

foreach предназначен для посещения каждого элемента в коллекции ровно один раз и не использует явный «индекс цикла»; если вы хотите больше контроля над циклом и иметь индекс цикла, используйте for.

РЕДАКТИРОВАТЬ: Вы можете изменить элементы в коллекции, которые повторяются внутри цикла foreach. Например:

foreach(Chair ch in mychairs)
{
    ch.PaintColour = Colour.Green; //this alters the chair object *in* the collection.
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...