【问题标题】:While-loop with break instead of while(condition)使用 break 而不是 while(condition) 的 While 循环
【发布时间】:2014-01-14 09:30:57
【问题描述】:

好的 - 所以也许我累了,但我正在尝试找出一种方法来执行以下操作(看起来……更……优雅?)

  • 我有一个布尔值(我们称之为loopTwice)
  • loopTwice 被循环内容使用(并修改其行为)以执行互斥功能
  • 如果loopTwice 为真,我希望循环执行两次,首先值为真,然后值为假
  • 如果loopTwice 为假,我希望循环只执行一次,值为假
  • loopTwice 在循环之后没有使用,所以最终值是什么并不重要

...这似乎有足够的意义,但出于某种原因,我的大脑没有想出比 while 循环更优雅的方法,该循环在结束时有一个 if 条件并带有一个中断:

// loopTwice is already set as true or false
while (true) //this seems ugly, not to mention breakable...
{
    DoThis(loopTwice);          //these act slightly differently based upon loopTwice
    DoThat(loopTwice);          //these act slightly differently based upon loopTwice
    DoAnotherThing(loopTwice);  //these act slightly differently based upon loopTwice

    if (!loopTwice) break;
    loopTwice = false;
}

这段代码(嗯,不是这段代码,而是等效代码......)完全按照我的意愿工作,无需提供另一个变量(我想这不是一件坏事,但我看不到使用另一个变量任何比这个更优雅的循环...)

在我看来,我必须缺少一些东西(如果某事为真,则循环两次,如果某事为假,则循环一次,“假”值始终是最后一个 - 最好没有第二个变量,例如一个计数器或第二个标志来指示循环已经运行一次)。

使用计数器或标志实际上更优雅吗? (我想对于过去几十年的计算机,它并没有真正冒破坏内存要求或任何东西的风险,是吗......)。将其分解为一个函数并使用递归会更优雅吗?嗯……

优雅,当然,在旁观者的眼中......

【问题讨论】:

    标签: c# loops


    【解决方案1】:

    这种感觉就像一个“倒计时”循环,但带有布尔值。您可以找出要使用的布尔值:

    var iterations = new[] {true,false}.SkipUntil(e => e == loopTwice);
    // or
    var iterations = new[] {true,false}.Skip(loopTwice ? 0 : 1);
    // or
    var iterations = loopTwice? new[] {true, false} : new[] {false};
    

    然后使用它们:

    foreach (var b in iterations) {
        DoThis(b);
        DoThat(b);
        DoAnotherThing(b);
    }
    

    【讨论】:

    • 我明白你的意思,除了示例抽象只调用两个函数(每种情况下一个),而我的实际代码有七个函数调用,它们是相同的函数,但对布尔值的作用不同(嗯其中一些行为不同)
    • @CodeJocket 啊。那我来处理一般情况。
    【解决方案2】:

    我假设您有足够的通用代码用于两个循环迭代,因此将其保留为循环是有意义的。您可以轻松地将其编写为 do...while 循环:

    do {
      ....
    } while (!(loopTwice = !loopTwice));
    

    【讨论】:

    • 你的假设是正确的 - 我必须通过我的大脑运行这个......今天有点慢(我认为它在后台运行诺顿反病毒)......但它看起来像什么我正在寻找:-) - 稍后回来
    • 这与我最初认为的必须是可能的一致,但我认为我必须使用递归——即使它需要我分解成一个单独的函数。我很高兴你喜欢@SiLo 的简单回答!
    【解决方案3】:

    这样的东西会起作用还是让你喜欢?

    switch (count) {
         case 0:
            break;
         case 1:
            doThisThingSecond();
            goto case: 2;
         case 2:
            doThisThingFirst();
            break;
    }
    

    【讨论】:

    • C# 不允许一个案例落入另一个案例。但是,如果您真的愿意,它确实可以扩展 goto 语法以允许 goto case 2;。
    • 是的,肯。已更正
    【解决方案4】:

    只是在这里添加另一个方法,递归!

    void MyRecursiveMethod(bool repeat)
    {
       // Do something here.
    
       // Should we do this more than once?
       if(repeat)
         MyRecursiveMethod(false); // Don't do this indefinitely!
    }
    

    编辑:这还允许您在必要时轻松地将其扩展到 n 次迭代,而不仅仅是两次。

    例如,将来您决定可能需要执行此操作 3 次,您可以将其更改为 int repeatCount 而不是简单的 bool,然后每次递减。

    【讨论】:

    • 我喜欢它的简单性。
    • 虽然我并不急切地期待重构/分解成一个函数,但它比@hvd 提供的答案更“优雅”(在这个词的简单易读意义上) - 如令人钦佩的答案是 - 无论如何他已经获得了足够的分数:-P。谢谢你们!
    【解决方案5】:

    使用布尔标志来指示您想要循环多少次似乎让读者难以理解(至少,这一次)。我更喜欢这样的:

    int loops = someFlag ? 2 : 1;
    while(loops-- > 0) {
    
        DoThis(someFlag);
        DoThat(someFlag);
        DoAnotherThing(someFlag);
    
    }
    

    它清楚地表达了您的意图:如果标志为真,则循环 2 次,如果标志为假,则仅执行一次。此外,它可以让您在将来非常轻松地修改循环迭代。没有递归,没有额外的功能,对需要的迭代次数有弹性,可读性等等。

    编辑

    添加一个内部标志来表达在最终迭代中始终使用false 的意图,这对于所需的循环数量仍然具有弹性。此外,我更改为预先递减循环变量,因此内部循环不会与 0 进行比较:

    int loops = someFlag ? 2 : 1;
    while (--loops >= 0) {
        bool lastIter = loops == 0;
    
        DoThis(someFlag && !lastIter);
        ...
    }
    

    【讨论】:

    • 有趣...使用单独的变量,但还不错!严格来说,为了我的目的,它需要 someFlag 在最后一次迭代中始终为假,但我必须至少为用户名选择 +1 :-D
    • 我错过了这个要求。我已经编辑了我的答案以包含一个内部变量,该变量应该清楚地向读者表达意图(对我来说显然是一件大事)在最后一次迭代中让标志为假。
    【解决方案6】:

    重新考虑要求后,我真的建议添加另一种方法。包装另一个方法或一堆方法是一种非常常见的模式(外观等),并且会使您的代码非常易读。使用 Linq 和递归进行的所有这些混淆都偏离了您的初衷。除非您在 1980 年代的硬件上运行,否则添加额外的方法或变量对代码性能的影响可以忽略不计。

    这是我的另一个建议:

    void ExecuteWithFlag(bool withFlag)
    {
        DoSomething(withFlag);
        DoSomethingElse(withFlag);
        // etc.
    }
    
    void Execute()
    {
        ExecuteWithFlag(true);
        ExecuteWithFlag(false);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-07
      • 1970-01-01
      • 1970-01-01
      • 2021-04-15
      • 2017-03-03
      • 1970-01-01
      相关资源
      最近更新 更多