MrV*_*dez 35 c# language-design
据我了解,C#的foreach迭代变量是不可变的.
这意味着我不能像这样修改迭代器:
foreach (Position Location in Map)
{
//We want to fudge the position to hide the exact coordinates
Location = Location + Random(); //Compiler Error
Plot(Location);
}
Run Code Online (Sandbox Code Playgroud)
我无法直接修改迭代器变量,而是必须使用for循环
for (int i = 0; i < Map.Count; i++)
{
Position Location = Map[i];
Location = Location + Random();
Plot(Location);
i = Location;
}
Run Code Online (Sandbox Code Playgroud)
来自C++背景,我认为foreach是for循环的替代品.但是由于上述限制,我通常会回退使用for循环.
我很好奇,使迭代器不可变的原理是什么?
编辑:
这个问题更多的是一个好奇的问题,而不是一个编码问题.我很欣赏编码答案,但我不能将它们标记为答案.
此外,上面的例子过于简化了.这是我想要做的C++示例:
// The game's rules:
// - The "Laser Of Death (tm)" moves around the game board from the
// start area (index 0) until the end area (index BoardSize)
// - If the Laser hits a teleporter, destroy that teleporter on the
// board and move the Laser to the square where the teleporter
// points to
// - If the Laser hits a player, deal 15 damage and stop the laser.
for (int i = 0; i < BoardSize; i++)
{
if (GetItem(Board[i]) == Teleporter)
{
TeleportSquare = GetTeleportSquare(Board[i]);
SetItem(Board[i], FreeSpace);
i = TeleportSquare;
}
if (GetItem(Board[i]) == Player)
{
Player.Life -= 15;
break;
}
}
Run Code Online (Sandbox Code Playgroud)
我无法在C#的foreach中执行上述操作,因为迭代器是不可变的.我想(如果我错了,请纠正我),这是针对foreach语言的设计.
我对为什么foreach迭代器是不可变的感兴趣.
tyl*_*erl 25
让我们从一个愚蠢但说明性的例子开始:
Object o = 15;
o = "apples";
Run Code Online (Sandbox Code Playgroud)
在任何时候我们都不会觉得我们只是把数字15变成了一串苹果.我们知道这o只是一个指针.现在让我们以迭代器的形式执行此操作.
int[] nums = { 15, 16, 17 };
foreach (Object o in nums) {
o = "apples";
}
Run Code Online (Sandbox Code Playgroud)
再次,这真的没有任何成就.或者至少它不会完成任何编译.它肯定不会将我们的字符串插入到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);
}
Run Code Online (Sandbox Code Playgroud)
如果要进行编译,则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);
}
Run Code Online (Sandbox Code Playgroud)
那么,为什么Microsoft禁止您重新分配用于迭代的指针?清楚一件事 - 你不希望人们分配它认为他们已经改变了你在循环中的位置.易于实现另一个:变量可能隐藏一些内部逻辑,指示正在进行的循环的状态.
但更重要的是,您没有理由想要分配它.它表示循环序列的当前元素.如果您遵循编码恐怖,为其分配值会违反"单一责任原则"或" 卷曲定律 ".变量应该仅仅意味着一件事.
Jon*_*eet 14
如果变量是可变的,那可能会给出错误的印象.例如:
string[] names = { "Jon", "Holly", "Tom", "Robin", "William" };
foreach (string name in names)
{
name = name + " Skeet";
}
Run Code Online (Sandbox Code Playgroud)
有些人可能认为会改变数组内容.它达到了一点,但这可能是一个原因.我今晚将在我的注释规范中查找...
maj*_*tor 10
我认为它是人为的限制,不需要这么做.为证明这一点,请将此代码纳入考虑范围,并为您的问题提供可能的解决方案.问题是asign,但对象的内部更改不会出现问题:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<MyObject> colection =new List<MyObject>{ new MyObject{ id=1, Name="obj1" },
new MyObject{ id=2, Name="obj2"} };
foreach (MyObject b in colection)
{
// b += 3; //Doesn't work
b.Add(3); //Works
}
}
class MyObject
{
public static MyObject operator +(MyObject b1, int b2)
{
return new MyObject { id = b1.id + b2, Name = b1.Name };
}
public void Add(int b2)
{
this.id += b2;
}
public string Name;
public int id;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我不知道这个现象,因为我总是按照我描述的方式修改对象.