一尘不染

为什么C#foreach语句中的Iteration变量是只读的?

c#

据我了解,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迭代器是不可变的感兴趣。


阅读 272

收藏
2020-05-19

共1个答案

一尘不染

让我们从一个愚蠢但说明性的示例开始:

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禁止您重新分配用于迭代的指针?一件事很清楚-
您不希望有人指派他们以为他们在循环中已经改变了您的位置。易于实施:变量可能隐藏一些内部逻辑,以指示正在进行的循环状态。

但更重要的是,您没有理由
分配给它。它代表循环序列的当前元素。如果您遵循“编码恐怖”,则为其分配值将违反“单一责任原则”或柯里定律。变量仅意味着一件事。

2020-05-19