我正在尝试使用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
。答案 0 :(得分:2)
我正在尝试使用此常见问题解答中描述的取消令牌。
该博文使用动态任务并行(StartNew
和ContinueWith
)。动态任务并行是指你需要进行大量的CPU操作,并且在你已经处理它们之前你不知道你有多少操作(即,你处理的每个操作都可以向其添加零个或多个附加任务)处理)。
在您的情况下,您只有一个异步操作。因此,该文章中的方法对于您的用例来说是完全错误的。你原来的想法更正确。
你想要更像这样:
private async void OnLoginButtonClicked(object sender, EventArgs e)
{
// Cancel the previous attempt (if any) and start a new one.
this.cts?.Cancel();
this.cts = new CancellationTokenSource();
try
{
bool loginSuccess = await AsyncLoginTask(this.cts.Token);
// Resolve race condition where user cancels just as it completed.
this.cts.Token.ThrowIfCancellationRequested();
if (loginSuccess)
{
// Show main page
}
}
catch (OperationCanceledException ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
private async Task<bool> AsyncLoginTask(CancellationToken cancellationToken = default(CancellationToken))
{
// Pass the token to HttpClient()
}