【发布时间】:2023-09-19 15:35:01
【问题描述】:
我正在尝试使用this FAQ 中描述的取消令牌。这是我最初的想法:
private async void OnLoginButtonClicked(object sender, EventArgs e)
{
if (this.cancelToken == null)
{
this.cancelToken = new CancellationTokenSource();
}
try
{
bool loginSuccess = await AsyncLoginTask(this.cancelToken.Token);
if (loginSuccess)
{
// Show main page
}
}
catch (OperationCanceledException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
finally
{
this.cancelToken = null;
}
}
private async Task<bool> AsyncLoginTask(CancellationToken cancellationToken = default(CancellationToken))
{
// Pass the token to HttpClient()
}
现在我对其进行了调整,结果如下:
private async void OnLoginButtonClicked(object sender, EventArgs e)
{
this.cancelToken?.Dispose();
this.cancelToken = new CancellationTokenSource();
try
{
var ui = TaskScheduler.FromCurrentSynchronizationContext();
var loginTask = Task.Factory.StartNew(async () =>
{
bool loginSuccess = await AsyncLoginTask(this.cancelToken.Token);
}, this.cancelToken.Token);
var displayResults = loginTask.ContinueWith(resultTask =>
{
// How do I know if the login was successful?
// Because AsyncLoginTask() returns bool.
System.Diagnostics.Debug.WriteLine("done");
},
CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
ui);
var displayCancelledTasks = loginTask.ContinueWith(resultTask =>
{
System.Diagnostics.Debug.WriteLine("canceled");
},
CancellationToken.None,
TaskContinuationOptions.OnlyOnCanceled, ui);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
问题:
- 如何知道登录是否成功?因为
AsyncLoginTask()返回bool。 - 如何正确创建和销毁令牌以允许多次启动和取消操作?
- 如何处理任务中的任务?控制台中显示“完成”,而任务 (AsyncLoginTask) 尚未完成。
【问题讨论】:
-
How do I know if the login was successful? Because AsyncLoginTask() returns bool好吧,您可以在该任务中返回loginSuccess,这将给loginTask一个结果。但是...我的问题是为什么要将登录任务包装在任务中? -
我的旧代码 (
AsyncLoginTask) 是这样构建的(异步/等待返回 true/false)。现在我希望用户可以取消操作。在链接的文章中,这是处理任务和ContinueWith的推荐方式。所以我完成了我的任务。我应该继续抓OperationCanceledException吗? -
好吧,我还没有深入研究链接的文章,我必须说我不是这方面的专家......但是,由于登录已经可以选择提供取消令牌,稍后您的逻辑需要登录结果,一个简单的
await对我来说似乎更直观。您可以以适当的方式处理该取消。你能解释一下你的实际目标以及为什么你认为这次重构将有助于实现它吗? -
@testing,查看这篇博文:Async re-entrancy, and the patterns to deal with it。
-
内部任务退出,因为这就是
await的工作方式——它从第一个await返回,保存上下文并释放线程。你应该抓住OperationCanceledException,它是基类*.com/a/13040503/213550
标签: c# asynchronous async-await task cancellation