Почему операторы присваивания (=) недопустимы в цикле foreach
? Я использую C #, но я бы предположил, что аргумент такой же, как и для других языков, которые поддерживают foreach
(например, PHP). Например, если я сделаю что-то вроде этого:
string[] sArray = new string[5];
foreach (string item in sArray)
{
item = "Some assignment.\r\n";
}
я получаю сообщение об ошибке: «Невозможно назначить элементу, поскольку он является итерационной переменной foreach».
Вот ваш код:
foreach (string item in sArray)
{
item = "Some assignment.\r\n";
}
Вот грубое приближение того, что компилятор делает с этим:
using (var enumerator = sArray.GetEnumerator())
{
string item;
while (enumerator.MoveNext())
{
item = enumerator.Current;
// Your code gets put here
}
}
Свойство IEnumerator
доступно только для чтения, но это не имеет значения, поскольку вы пытаетесь присвоить локальной переменной item
новое значение. Проверка времени компиляции, не позволяющая вам сделать это, предусмотрена в основном для того, чтобы защитить вас от действий, которые не будут работать так, как вы ожидаете (т.е. изменение локальной переменной не окажет никакого влияния на основную коллекцию/последовательность).
Если вы хотите изменить внутреннюю структуру индексированной коллекции, такой как string[]
при перечислении, традиционным способом является использование цикла for
вместо foreach
:
for (int i = 0; i < sArray.Length; ++i)
{
sArray[i] = "Some assignment.\r\n";
}
В общем, если вы пытаетесь сделать это, вам нужно долго и тщательно обдумать свой дизайн, потому что вы, вероятно, используете не самую лучшую конструкцию. В данном случае лучшим ответом, вероятно, будет
string[] sArray = Enumerable.Repeat("Some assignment.\r\n", 5).ToArray();
В C# вместо такого цикла почти всегда можно использовать конструкции более высокого уровня. (И в C++, но это уже совсем другая тема)
Вы не можете изменять массив, по которому выполняется foreach. Вместо этого используйте следующий код:
string[] sArray = new string[5];
for (int i=0;i<sArray.Length;i++)
{
item[i] = "Some Assignment.\r\n";
}
Потому что так сказано в спецификации языка.
Но если серьезно, не все последовательности являются массивами или объектами, которые можно логически модифицировать или записывать. Например:
foreach (var i in Enumerable.Range(1, 100)) {
// modification of `i` will not make much sense here.
}
Хотя было бы технически возможно, чтобы i = something;
изменяли локальную переменную, это может вводить в заблуждение (вы можете подумать, что это действительно что-то меняет под капотом, а это не в случае).
Для поддержки такого рода последовательностей IEnumerable
не требует аксессора set
для своего свойства Current
, что делает его доступным только для чтения. Таким образом, foreach
не может изменять базовую коллекцию (если она существует) с помощью свойства Current
.
Цикл foreach
предназначен для перебора объектов в коллекции, а не для их назначения — это просто дизайн языка.
Также из MSDN:
«Эта ошибка возникает, когда присваивание переменной происходит в только контекст. Контексты только для чтения включают переменные итерации foreach, с использованием переменных и фиксированных переменных. Чтобы устранить эту ошибку, избегайте присваивания переменной оператора при использовании блоков, foreach операторы и фиксированные операторы».
Ключевое слово foreach просто перечисляет экземпляры IEnumerable (получение экземпляров IEnumerator, вызвав метод Метод ПолучитьПеречислитель()). IEnumerator доступен только для чтения, поэтому значения не могут быть изменено с помощью IEnumerator = не может быть изменяется с использованием контекста foreach.
Потому что вы не можете использовать цикл foreach
для изменения массива, который вы просматриваете. Цикл итерирует по массиву, поэтому, если вы попытаетесь изменить то, что он итерирует, может произойти неожиданное поведение. Кроме того, как указали Дарин и ДМан, вы перебираете IEnumerable
, который сам доступен только для чтения.
PHP создает копию массива в своем цикле foreach
и выполняет итерацию по этой копии, если вы не используете ссылки, в этом случае вы будете изменять сам массив.
Вы не можете изменить список, который проходит через "ForEach".
Лучше всего просто создать временный список для хранения элементов, которые вы хотите использовать.
Было бы вполне возможно позволить его изменить. Однако что же это тогда означает? Это будет выглядеть так, как будто базовое перечисление было изменено, а это не так (можно было бы разрешить и это, но у этого есть свои недостатки).
Таким образом, у вас будет код, который люди, естественно, прочитают как указывающий на что-то иное, чем то, что произошло на самом деле. Учитывая, что цель компьютерного языка в первую очередь состоит в том, чтобы его понимали люди (компиляторы имеют дело с балансом, установленным против них, если только вы не используете ассемблер, машинный код или подходящее название Brainf**k), это указывало бы на недостаток в коде. язык.