【问题标题】:C# Break out of loop on button pressC#在按钮按下时跳出循环
【发布时间】:2009-08-03 11:32:39
【问题描述】:

我有一个简单的 C# foreach 循环,当按下按钮时如何跳出循环?它不在 backgroundWorker 线程中,所以我不能使用 backgroundWorker.CancellationPending。

【问题讨论】:

  • foreach 循环是否在单独的线程上使用?还是在 UI 线程上?
  • 循环是否在另一个线程上运行?
  • 如果循环在 UI 线程上,那么直到包含循环的函数完成后才会到达按钮单击事件处理程序。
  • 我同意,如果您只想定期检查某个事件,那就有点过头了。
  • 为什么投反对票?人们是否认为在按下按钮时终止中间循环是不明智的?

标签: c# foreach


【解决方案1】:

在表单中创建一个布尔标志。将事件处理程序附加到按钮单击事件并在事件处理程序中将标志设置为 true。

检查循环中的标志,如果为真,则调用“break”。 (更好的选择是使用 while 循环而不是 for 循环并检查 while 条件中的标志)

显然,for 循环需要在某种形式的后台线程上,否则 GUI 将无法响应。如果您不知道如何执行此操作,请查看ThreadPool.QueueUserWorkItemBackgroundWorker。如果您确实使用了 BackgroundWorker,则可以使用内置的 CancelAsync() 方法,而不是编写自己的取消标志。

[编辑:正如其他人所指出的(如下)并更深入地讨论了herehere;您确实需要在访问 bool 之前锁定或将其标记为 volatile]

[不要忘记在开始循环之前设置标志的正确状态。]

【讨论】:

  • 显然标志必须是可变的,或者访问必须同步。
  • efraim,为什么需要同步对简单布尔字段的访问?用户不能很好地同时按下启动循环的按钮和取消循环的按钮,可以吗?
  • 因为编译器可以合法地优化掉任何此类访问,如果它认为合适的话。
  • @Simon:最坏的情况实际上是它会永远循环,因为编译器永远不会尝试访问该变量。
  • 即使是一个布尔值,当从另一个线程访问时,也需要lock(作为内存屏障)或volatile保证它将被重新读取;可以显示它卡在寄存器中的示例,否则:stackoverflow.com/questions/458173/…
【解决方案2】:

这是一个不太好的解决方案。

在您的循环的每次迭代中调用Application.DoEvents()。在 Button-Click 上将变量设置为 True 并在循环中检查该变量。如果为真,则中断,否则继续。

正如我所说,这不是一个很好的解决方案。 Application.DoEvents() 可能非常危险。最好的选择是有一个后台线程。

【讨论】:

  • 我同意。这是一个不太好的解决方案。不要使用 DoEvents。使用后台工作者或 ThreadPool.QueueUserWorkItem() 将 for 循环正确放置在后台线程上
  • +1 用于实际工作的东西,即使它是一个相当丑陋且无法扩展的解决方案......您可以为其添加一个计数器并在每 n:th 迭代中调用 DoEvents 以降低性能命中。
【解决方案3】:

您可以按照 Aamir 的建议使用 DoEvents 作为快速修复。

要获得更具可扩展性和可维护性的解决方案,您需要将工作转移到单独的线程中。然后让按钮单击事件设置一个标志来停止循环是相当微不足道的。另一方面,将结果传达回 UI 线程需要做更多的工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-01
    • 2016-02-29
    • 2013-04-29
    • 2022-01-25
    • 1970-01-01
    • 2012-07-14
    • 1970-01-01
    相关资源
    最近更新 更多