C# 在FOR循环中修改索引变量是否是一种好的做法?

C# 在FOR循环中修改索引变量是否是一种好的做法?,c#,C#,鉴于代码: for (int i = 1; i <= 5; i++) { // Do work } 在我看来,这太令人困惑了。在这种情况下,最好使用while循环。我会说是的,但仅在特定情况下 这可能有点混乱-如果我设置I=4,它是否会在下一次迭代之前递增 这可能是一种代码气味的迹象——也许您应该在之前执行LINQ查询,并且只处理相关元素 小心使用 这是可以接受的,但是,我个人认为这应该避免。由于它正在创建大多数开发人员都无法预料的

鉴于代码:

for (int i = 1; i <= 5; i++)
        {
            // Do work
        }

在我看来,这太令人困惑了。在这种情况下,最好使用
while
循环。

我会说是的,但仅在特定情况下

这可能有点混乱-如果我设置
I=4
,它是否会在下一次迭代之前递增

这可能是一种代码气味的迹象——也许您应该在之前执行LINQ查询,并且只处理相关元素


小心使用

这是可以接受的,但是,我个人认为这应该避免。由于它正在创建大多数开发人员都无法预料的代码,我发现它导致了一些不可维护的东西

就个人而言,如果您需要这样做,我建议切换到while循环:

int i=1;
while (i <= 5)
{
    if (i == 2)
        i = 4;

    ++i;
}
inti=1;
虽然(我是的,它是可以的。因为有大量的可能情况,你一定会发现一个例外,它被认为是良好的实践

但是停止对事物的理论分析,我会说:。不要这样做。
它变得相当复杂,很难阅读和/或理解。我宁愿看到类似于
continue
语句的内容,尽管我也不太喜欢它。

是的

在解析数据的应用程序中经常可以看到这种情况。例如,假设我正在扫描一个二进制文件,并且基本上正在查找某些数据结构。我可能有执行以下操作的代码:

int SizeOfInterestingSpot = 4;
int InterestingSpotCount = 0;
for (int currentSpot = 0; currentSpot < endOfFile; currentSpot++)
{
    if (IsInterestingPart(file[currentSpot])
    {
        InterestingSpotCount++;
        //I know that I have one of what I need ,and further, that this structure in the file takes 20 bytes, so...
        currentSpot += SizeOfInterestingSpot-1;  //Skip the rest of that structure.

    }
}
int-sizeofindertestingspot=4;
int InterestingSpotCount=0;
对于(int currentSpot=0;currentSpot
引用Petar Minchev的话:


在我看来,这太令人困惑了。 在这种情况下,最好使用while循环

我想说的是,通过这样做,你必须意识到一些可能发生的事情,比如无限循环、过早取消的循环、奇怪的变量值或数学,当它们基于你的索引时,以及主要(不排除任何其他)基于你的索引和其他被失败循环修改的变量的执行流问题


但是如果你遇到这样的情况,那就去做吧。

一个例子是删除符合某些条件的项目:

for (int i = 0; i < array.size(); /*nothing*/)
{
    if (pred(array[i]))
        i++;
    else
        array.erase(array.begin() + i);
}

编辑
哦,对不起,我的代码是C++,问题是C语言,但是这个想法是一样的:

for (int i = 0; i < list.Length; /*nothing*/)
{
    if (pred(list[i]))
        i++;
    else
        list.RemoveAt(i);
}
或者以稍微现代一点的风格

list = list.Where(pred);

(这里的
列表
应该是
IEnumerable

一个例子可以是
for
循环,您希望在特定条件下重复当前迭代或返回到上一个迭代,甚至跳过一定数量的迭代(而不是数字的
continue

但是这些情况很少见,即使在这些情况下,考虑<<代码> > <代码>循环只是<>代码> <<代码> > <代码> do>代码>和其他可以使用的工具。因此,将此视为不好的实践,并设法避免它。您的代码也将不那么易读。


因此,作为结论:这是可以实现的(不是在
foreach
中)但是尽量避免这种情况使用
等等。

我个人认为,如果算法的逻辑要求正常的线性迭代行为,但跳过或重复某些迭代,那么就去做。然而,我也同意大多数人的观点,这对我们来说是不正常的年龄,如果我站在你的立场上,我一定会给出一两条评论,说明为什么会发生这种情况


对于这样的事情,一个完全有效的用例可能是解析一个罗马数字字符串。对于字符串中的每个字符索引,请查看该字符和下一个字符。如果下一个字符的数值大于当前字符,请从下一个字符的值中减去当前字符的值,将结果添加到总数中,然后跳过下一个字符下一个字符是通过增加当前索引。否则,只需将当前字符的值添加到运行总数中并继续。

除非你能提供一个好的用例,否则怎么可能呢?如果你有一个好的用例,我们将讨论;)通常被认为是不好的做法。但有时……我认为它永远都不“好”,但有时“好”不是优先考虑的问题。我没有提出这个问题的好理由。我维护了一些遗留代码,这些代码在for循环中修改了迭代器,这让我有点陷入了一个循环(没有双关语!)这就是促使我提出这个问题的原因。我的信念是不这样做,但我想从开发者社区中得到一点感觉。-感谢所有花时间参与这个话题的人。很难相信stackoverflow警方没有因为他们使用的100个理由中的一个而关闭这个问题。同意,这是关于意图。一个循环在它的声明中,它从0开始,在42结束,然后增加2。你不希望它在它存在的过程中做完全不同的事情。我不知道是否有任何严格的“正确”。回答这个问题。有些人可能会认为这是一个风格问题。但我同意这确实会增加混乱。就我个人而言,我觉得这作为一个while循环更容易理解。它很可能是;但我不认为它作为FOR循环是不正确或错误的。如前所述,这将导致一个off-by-one错误(跳过“有趣的点”后)您将开始下一个迭代(距离太远).具有讽刺意味的是,您已经说明了为什么以这种方式使用
for
是危险的。这更像是一个伪代码说明了这个想法,而不是没有bug的实际正确代码;但我还是会继续修复它。我同意。我在代码中避免了这一点,因为我认为这会让人难以阅读。当我看到for循环时,我希望代码是正确的把它改成b
for (auto it = array.begin(); it != array.end(); /*nothing*/)
{
    if (pred(*it))
        ++it;
    else
        it = array.erase(it);
}
for (int i = 0; i < list.Length; /*nothing*/)
{
    if (pred(list[i]))
        i++;
    else
        list.RemoveAt(i);
}
list.RemoveAll(x => !pred(x));
list = list.Where(pred);