据我了解,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); }
我不能直接修改迭代器变量,而必须使用for循环
for (int i = 0; i < Map.Count; i++) { Position Location = Map[i]; Location = Location + Random(); Plot(Location); i = Location; }
来自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; } }
我不能在C#的foreach中完成上述操作,因为迭代器i是不可变的。我认为(如果我错了,请纠正我),这特定于语言中的foreach设计。
我对为什么foreach迭代器是不可变的感兴趣。
让我们从一个愚蠢但说明性的示例开始:
Object o = 15; o = "apples";
我们从来没有感觉到我们只是将数字15变成了一串苹果。我们知道那o仅仅是一个指针。现在,以迭代器形式进行操作。
o
int[] nums = { 15, 16, 17 }; foreach (Object o in nums) { o = "apples"; }
再一次,这真的什么也做不了。或至少编译它 不会 完成任何工作。它当然不会将我们的字符串插入到int数组中- 这是不允许的,而且我们知道这o仍然只是一个指针。
让我们举个例子:
如果要进行编译,则Location在您的示例中,会突出显示引用中的值Map,然后您将其更改为引用一个新值Position(由加法运算符隐式创建)。从功能上讲,它等效于此(可以编译):
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禁止您重新分配用于迭代的指针?一件事很清楚- 您不希望有人指派他们以为他们在循环中已经改变了您的位置。易于实施:变量可能隐藏一些内部逻辑,以指示正在进行的循环状态。
但更重要的是,您没有理由 要 分配给它。它代表循环序列的当前元素。如果您遵循“编码恐怖”,则为其分配值将违反“单一责任原则”或柯里定律。变量仅意味着一件事。