从在异步方法内启动的while循环退出

时间:2019-06-01 11:34:56

标签: c# asynchronous while-loop

如何打破异步方法内部的while循环。请参考下面的代码

我尝试了很多方法,但是没有一个对我有用

async void TotalTimer(string time)
{
    while (true)
    {
        TimeSpan timesp = DateTime.Now - DateTime.Parse(time);
        TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
        await Task.Delay(1000);

        if (string.IsNullOrEmpty(time))
        {
            break;
        }
    }
}

我需要停止循环并退出循环


更新的代码:

async Task TotalTimer(CancellationToken token)
{
    var intime = await App.Database.GetRecentIn();
    InTime = DateTime.Parse(intime.datetime).ToString("hh:mm tt");


    while (!token.IsCancellationRequested)
    {
        TimeSpan timesp = DateTime.Now - DateTime.Parse(intime.datetime);
        TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
        Console.WriteLine(TotalTime); // to see it's working
        await Task.Delay(1000);

        if (token.IsCancellationRequested)
        {
            break;
        }
    }
}

void StatCounting()
{
    var cts = new CancellationTokenSource();
   _= TotalTimer(cts.Token);
}

void StopCounting()
{
    var cts = new CancellationTokenSource();
    cts.Cancel();
   _= TotalTimer(cts.Token);

    _=Finalize();
}

3 个答案:

答案 0 :(得分:3)

像这样使用CancellationToken

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Program
    {
        private string TotalTime;

        static void Main(string[] args)
        {
            new Program().Run();
        }

        private void Run()
        {
            var cts = new CancellationTokenSource();
            TotalTimer("00:00:00", cts.Token);

            Console.ReadLine(); // waits for you to press 'Enter' to stop TotalTimer execution.
            cts.Cancel();
            Console.WriteLine("Press 'Enter' to exit the program.");
            Console.ReadLine();  // waits for you to press 'Enter' to exit the program. See, TotalTimer stopped.
        }

        // your original method modified
        async void TotalTimer(string time, CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                TimeSpan timesp = DateTime.Now - DateTime.Parse(time);
                TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
                Console.WriteLine(TotalTime); // to see it's working
                await Task.Delay(5000, token);
            }
        }
    }
}

更新

@Henk Holterman,根据编辑历史记录if (string.IsNullOrEmpty(time))似乎是从外面打破循环的尝试。但这是没有意义的,有两个原因:

  • 字符串是不可变的
  • 如果time为空或为空,则DateTime.Parse(time)(在原始帖子中)在检查前抛出

将令牌添加到Task.Delay是个好主意。这样做可以节省资源,尽管对可观察的行为没有影响。

Update2

@Argon,代码独立于wpfwinformsconsole等。参见下面的最小wpf示例。我检查了它的工作情况。如果某些操作不适用于您的具体代码,则您可能会向我们隐藏一些细节。

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private string TotalTime;
        private CancellationTokenSource cts;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            cts = new CancellationTokenSource();
            TotalTimer("00:00:00", cts.Token);
        }

        async void TotalTimer(string time, CancellationToken token)
        {
            try
            {
                while (!token.IsCancellationRequested)
                {
                    TimeSpan timesp = DateTime.Now - DateTime.Parse(time);
                    TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
                    label1.Content = TotalTime;
                    await Task.Delay(5000, token);
                }
            }
            catch(TaskCanceledException)
            {
                label1.Content = "Canceled";
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            cts.Cancel();
        }
    }
}

答案 1 :(得分:2)

break方法中使用async很好。

这很好:

async void Main()
{
    await TotalTimer();
    Console.WriteLine("Done.");
}

async Task TotalTimer()
{
    while (true)
    {
        await Task.Delay(1000);

        if (true)
        {
            break;
        }
    }
}

等待一秒钟,然后将Done.写入控制台。

您的代码只是不会更改time,因此它永远不会达到break

除了您的async方法应该返回Task而不是void之外。

答案 2 :(得分:-1)

感谢您的努力。我想出了一种方法来停止循环。我已经定义了布尔值并在while循环中检查了它以打破循环。它最有可能@Enigmativitys回答。

bool hasToStop = false;
while (true)
            {
                TimeSpan timesp = DateTime.Now - DateTime.Parse(intime.datetime);
                TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
                Console.WriteLine(TotalTime); // to see it's working
                await Task.Delay(1000);

                if (hasToStop)
                {
                    Console.WriteLine("Stoped");
                    break;
                }
            }