Давайте начнем с глупого, но наглядного примера:
Object o = 15;
o = "apples";
Ни в коем случае не создается впечатление, что мы просто превратили число 15 в ряд яблок. Мы знаем, что o
это просто указатель. Теперь давайте сделаем это в форме итератора.
int[] nums = { 15, 16, 17 };
foreach (Object o in nums) {
o = "apples";
}
Опять же, это действительно ничего не дает. Или, по крайней мере, ничего не даст, если его скомпилировать. Это, конечно, не вставит нашу строку в массив int - это недопустимо, и мы знаем, что o
это просто указатель в любом случае.
Давайте рассмотрим ваш пример:
foreach (Position Location in Map)
{
//We want to fudge the position to hide the exact coordinates
Location = Location + Random(); //Compiler Error
Plot(Location);
}
Если это скомпилировать, Location
в вашем примере убирается со ссылкой на значение в Map
, но затем вы изменяете его, ссылаясь на новый Position
(неявно созданный оператором сложения). Функционально это эквивалентно этому (который компилируется):
foreach (Position Location in Map)
{
//We want to fudge the position to hide the exact coordinates
Position Location2 = Location + Random(); //No more Error
Plot(Location2);
}
Итак, почему Microsoft запрещает вам переназначать указатель, используемый для итерации? Ясность с одной стороны - вы не хотите, чтобы люди, назначенные на это, думали, что изменили вашу позицию в цикле. Простота реализации для другого: переменная может скрывать некоторую внутреннюю логику, указывающую состояние текущего цикла.
Но, что более важно, у вас нет оснований хотеть назначить его. Он представляет текущий элемент последовательности цикла. Присвоение ему значения нарушает «Принцип единой ответственности» или Закон Керли , если вы следуете Кодовому Ужасу. Переменная должна означать только одну вещь.