Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C#中重新启动foreach循环?_C#_Loops_Foreach_Reserved Words - Fatal编程技术网

在C#中重新启动foreach循环?

在C#中重新启动foreach循环?,c#,loops,foreach,reserved-words,C#,Loops,Foreach,Reserved Words,如何在C#中重新启动foreach循环 例如: Action a; foreach(Constrain c in Constrains) { if(!c.Allows(a)) { a.Change(); restart; } } restart这里类似于continue或break,但它从一开始就重新启动foreach 这就像将循环的计数器再次设置为0一样 这在C#中可能吗 编辑:我要感谢Mehrdad Afshari和Mahesh Velaga让我在

如何在C#中重新启动
foreach
循环

例如:

Action a;
foreach(Constrain c in Constrains)
{
   if(!c.Allows(a))
   {
      a.Change();
      restart;
   }
}
restart
这里类似于
continue
break
,但它从一开始就重新启动foreach 这就像将
循环的
计数器再次设置为0一样

这在C#中可能吗


编辑:我要感谢Mehrdad Afshari和Mahesh Velaga让我在当前的实现中发现了一个bug(index=0),否则就不会被发现。

使用好的旧
转到

restart:
foreach(Constrain c in Constrains)
{
   if(!c.Allows(a))
   {
      a.Change();
      goto restart;
   }
}
如果你100%的时间都是因为某种原因被诊断患有恐惧症(没有原因这不是一件好事),你可以尝试使用一个标志来代替:

bool restart;
do {
   restart = false;
   foreach(Constrain c in Constrains)
   {
      if(!c.Allows(a))
      {
         a.Change();
         restart = true;
         break;
      }
   }
} while (restart);
void Main()
{
数不清的犯人;
某物a;
而(!TryChangeList(cons,a)){}
}
//名称tryChangeList显示了列表将被更改的意图
私有bool TryChangeList(IEnumerable约束,SomeObject a)
{
foreach(约束中的var con)
{
如果(!c.允许(a))
{
a、 改变();
返回false;
}
}
返回true;
}

一种方法是使用,正如您已经提到的:

在这里重新启动就像继续或中断一样 但它会重新启动foreach 开始时类似于将for循环的计数器再次设置为0

动作a;
对于(var index=0;index
虽然这是一条非常古老的线索,但没有一个答案对该代码的语义给予了应有的关注:

  • 您对
    a
  • 如果
    a
    破坏了其中任何一个,请尝试另一个
    a
    并将其推过链条
也就是说,
a.Change()
应与约束检查循环分离,同时遵循CQS原则:

while (!MeetsConstraints(a))
{
    a.Change();
}

bool MeetsConstraints(Thing a)
{
    return Constraints.All(c => c.Allows(a));
}


没有后路,没有丑陋的循环,只是简单和干净

这是错误的
index=-1
可以工作,如果可枚举项是索引可访问的,但即使在这种情况下,它也会使代码难以读取,并且使意图不明确。这是一个因盲目恐惧症而使事情变得更糟的完美例子。至少,对于
goto
,目的非常清楚。+1这是第一个想到的解决方案——为什么不使用for循环呢?为什么要创建一个bastardized foreach解决方案。@Chuck:可能是因为并非所有集合都可以通过索引访问?@Chuck这种方法还有其他问题。它很容易出错(刚刚用
index=0
对答案进行的原始修订证明了这一点)。用指数操纵事物只会带来更多的问题。更不用说操纵循环索引是不受欢迎的了。@Chuck:是的,但我认为你不应该通过操纵循环内的循环索引来重置
for
循环。我相信
goto
比将索引设置为-1更具可读性,也更不容易出错。了解需要在何处使用这种重新启动可能会很有趣。您正在某种算法中使用可变对象列表。你能分享你试图解决的实际问题吗?实际问题:一些代理试图在一个环境中移动。环境中存在障碍。在每个代理决定下一个动作是什么之后,环境检查代理是否会跨越障碍,如果是,环境允许代理选择另一个动作;在这里,我需要重新启动foreach循环,以便使用新选择的操作再次检查所有屏障。。我希望这能说明…+1。在这种情况下,重构通常是一个很好的解决方案,只要它是可行的,并且不会使事情变得更复杂。@John-如果您将IList更改为IEnumerable,它也会适用于IEnumerable。Lei不是下选者,但您应该将
IList
更改为
IEnumerable
。我已经解释过了。问题并没有局限于
IList
,正确的方法名称应该是
checkConstraints和fNotMetChangeaOnce,后面没有checkingConstraints
。或者,您可以删除行
a.Change()
并将其放入
while
主体中,使该方法成为纯粹的约束检查:
while(!meetConstraints(cons,a)){a.Change();}
。重构是个好主意,但要做得恰当。这样,该方法仍然混合了值更改和约束检查逻辑,而值更改现在分布在两个方法中。您需要先处理原始方法。@John:的确如此。你必须处理潜在的例外情况。。。这最终会导致使用
语句生成一个
,在这一点上,您会意识到,您首先不应该抛弃foreach
!小心!在dotnet3.5及更高版本(LINQ等)中,foreach()可以拉入闭包。此解决方案或跳出循环的任何其他解决方案将正确处理闭包。但是仔细想想;这是一个精心设计可以节省大量调试的地方。你为什么要这样做?我是说它解决了什么问题?我很高兴看到原作是什么,而不是人为的代码。我喜欢“好老的goto”和“gotophobia”。然而,你对哥特恐惧症患者的建议一点也不好
break
是一个带有另一个名称的
goto
。它只会跳转到错误的位置,您必须使用一个标志和一个额外的do while循环来修复它——这比解决方案1要难看得多。你可能知道:-)但一旦你想建议一个非后进版本,它应该是真正的非后进版本。或者你可以完全删除那个部分,因为它已经被马赫什的答案覆盖了。@chiccodoro gotophobists倾向于认为
break
出于某种原因是可以的。@Wolfzoon它是真的break是一种goto,就像扔和扔一样。不同之处在于,它是一种标准使用的goto,具有定义良好的结构,现代经验丰富的程序员可以使用它
Action a;
for(var index = 0; index < Constratins.Count; index++)
{
   if(!Constraints[index].Allows(a))
   {
      a.Change();
      index = -1; // restart
   }
}
for (var en = Constrains.GetEnumerator(); en.MoveNext(); )
{
    var c = en.Current;
    if (!c.Allows(a))
    {
        a.Change();
        en = Constrains.GetEnumerator();
    }
}
while (!MeetsConstraints(a))
{
    a.Change();
}

bool MeetsConstraints(Thing a)
{
    return Constraints.All(c => c.Allows(a));
}