Почему операторы присваивания (=) недопустимы в цикле foreach?

Почему операторы присваивания (=) недопустимы в цикле foreach ? Я использую C #, но я бы предположил, что аргумент такой же, как и для других языков, которые поддерживают foreach (например, PHP). Например, если я сделаю что-то вроде этого:

string[] sArray = new string[5];

foreach (string item in sArray)
{
   item = "Some assignment.\r\n";
}

я получаю сообщение об ошибке: «Невозможно назначить элементу, поскольку он является итерационной переменной foreach».

26
задан Carl Manaster 23 August 2010 в 16:55
поделиться

9 ответов

Вот ваш код:

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.Current доступно только для чтения, но это не имеет значения, поскольку вы пытаетесь присвоить локальной переменной item новое значение. Проверка времени компиляции, не позволяющая вам сделать это, предусмотрена в основном для того, чтобы защитить вас от действий, которые не будут работать так, как вы ожидаете (т.е. изменение локальной переменной не окажет никакого влияния на основную коллекцию/последовательность).

Если вы хотите изменить внутреннюю структуру индексированной коллекции, такой как string[] при перечислении, традиционным способом является использование цикла for вместо foreach:

for (int i = 0; i < sArray.Length; ++i)
{
    sArray[i] = "Some assignment.\r\n";
}
64
ответ дан 28 November 2019 в 06:13
поделиться

В общем, если вы пытаетесь сделать это, вам нужно долго и тщательно обдумать свой дизайн, потому что вы, вероятно, используете не самую лучшую конструкцию. В данном случае лучшим ответом, вероятно, будет

string[] sArray = Enumerable.Repeat("Some assignment.\r\n", 5).ToArray();

В C# вместо такого цикла почти всегда можно использовать конструкции более высокого уровня. (И в C++, но это уже совсем другая тема)

2
ответ дан 28 November 2019 в 06:13
поделиться

Вы не можете изменять массив, по которому выполняется foreach. Вместо этого используйте следующий код:

string[] sArray = new string[5]; 

for (int i=0;i<sArray.Length;i++)
{
    item[i] = "Some Assignment.\r\n";
}
1
ответ дан 28 November 2019 в 06:13
поделиться

Потому что так сказано в спецификации языка.

Но если серьезно, не все последовательности являются массивами или объектами, которые можно логически модифицировать или записывать. Например:

foreach (var i in Enumerable.Range(1, 100)) {
   // modification of `i` will not make much sense here.
}

Хотя было бы технически возможно, чтобы i = something; изменяли локальную переменную, это может вводить в заблуждение (вы можете подумать, что это действительно что-то меняет под капотом, а это не в случае).

Для поддержки такого рода последовательностей IEnumerable не требует аксессора set для своего свойства Current , что делает его доступным только для чтения. Таким образом, foreach не может изменять базовую коллекцию (если она существует) с помощью свойства Current .

6
ответ дан 28 November 2019 в 06:13
поделиться

Поскольку IEnumerable доступен только для чтения.

2
ответ дан 28 November 2019 в 06:13
поделиться

Цикл foreach предназначен для перебора объектов в коллекции, а не для их назначения — это просто дизайн языка.

Также из MSDN:

«Эта ошибка возникает, когда присваивание переменной происходит в только контекст. Контексты только для чтения включают переменные итерации foreach, с использованием переменных и фиксированных переменных. Чтобы устранить эту ошибку, избегайте присваивания переменной оператора при использовании блоков, foreach операторы и фиксированные операторы».

Ключевое слово foreach просто перечисляет экземпляры IEnumerable (получение экземпляров IEnumerator, вызвав метод Метод ПолучитьПеречислитель()). IEnumerator доступен только для чтения, поэтому значения не могут быть изменено с помощью IEnumerator = не может быть изменяется с использованием контекста foreach.

5
ответ дан 28 November 2019 в 06:13
поделиться

Потому что вы не можете использовать цикл foreach для изменения массива, который вы просматриваете. Цикл итерирует по массиву, поэтому, если вы попытаетесь изменить то, что он итерирует, может произойти неожиданное поведение. Кроме того, как указали Дарин и ДМан, вы перебираете IEnumerable, который сам доступен только для чтения.

PHP создает копию массива в своем цикле foreach и выполняет итерацию по этой копии, если вы не используете ссылки, в этом случае вы будете изменять сам массив.

4
ответ дан 28 November 2019 в 06:13
поделиться

Вы не можете изменить список, который проходит через "ForEach".

Лучше всего просто создать временный список для хранения элементов, которые вы хотите использовать.

0
ответ дан 28 November 2019 в 06:13
поделиться

Было бы вполне возможно позволить его изменить. Однако что же это тогда означает? Это будет выглядеть так, как будто базовое перечисление было изменено, а это не так (можно было бы разрешить и это, но у этого есть свои недостатки).

Таким образом, у вас будет код, который люди, естественно, прочитают как указывающий на что-то иное, чем то, что произошло на самом деле. Учитывая, что цель компьютерного языка в первую очередь состоит в том, чтобы его понимали люди (компиляторы имеют дело с балансом, установленным против них, если только вы не используете ассемблер, машинный код или подходящее название Brainf**k), это указывало бы на недостаток в коде. язык.

0
ответ дан 28 November 2019 в 06:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: