如何打破异步方法内部的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();
}
答案 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,代码独立于wpf
,winforms
,console
等。参见下面的最小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;
}
}