Шаблон повторного входа 5: отмена предыдущего вызова
Мне нужна задача повторного ввода и реализации кода, аналогичного https://blogs.msdn.microsoft.com/lucian/2014/03/03/async-re-entrancy-and-the-patterns-to-deal-with-it/ (шаблон 5)
но мне интересно, если распоряжение CancellationTokenSource не отсутствует. Моя реализация добавляет его в.ContinueWith
private Task _fooAsyncTask;
private CancellationTokenSource _fooAsyncCancellation;
public async Task Button1Click()
{
// Assume we're being called on UI thread... if not, the two assignments must be made atomic.
// Note: we factor out "FooHelperAsync" to avoid an await between the two assignments.
// without an intervening await.
_fooAsyncCancellation?.Cancel();
_fooAsyncCancellation = new CancellationTokenSource();
_fooAsyncTask = FooHelperAsync(_fooAsyncCancellation.Token);
await _fooAsyncTask.ContinueWith(task =>
{
_fooAsyncCancellation.Dispose();
_fooAsyncCancellation = null;
});
}
private async Task FooHelperAsync(CancellationToken cancel)
{
try { if (_fooAsyncTask != null) await _fooAsyncTask; }
catch (OperationCanceledException) { }
cancel.ThrowIfCancellationRequested();
await FooAsync(cancel);
}
private async Task FooAsync(CancellationToken cancel)
{
//
}
Это верно?
1 ответ
Вы должны изменить свой код на
- установить _
fooAsyncCancellation
вnull
в потоке пользовательского интерфейса (в продолжение это не так) - гарантировать, что вы располагаете CTS, созданным для этой задачи.
Вот модифицированный код
Task _fooAsyncTask;
CancellationTokenSource _fooAsyncCancellation;
async void button1_Click(object sender, EventArgs e)
{
_fooAsyncCancellation?.Cancel();
using (var cts = new CancellationTokenSource())
{
_fooAsyncCancellation = cts;
try
{
await FooAsyncHelper(cts.Token);
}
catch (OperationCanceledException) { }
if (_fooAsyncCancellation == cts)
{
_fooAsyncCancellation = null;
}
}
}
async Task FooAsyncHelper(CancellationToken cancellationToken)
{
try
{
if (_fooAsyncTask != null)
{
await _fooAsyncTask;
}
}
catch (OperationCanceledException) { }
cancellationToken.ThrowIfCancellationRequested();
await FooAsync(cancellationToken);
}
async Task FooAsync(CancellationToken cancellationToken)
{
// just some sample work to do
for (int i = 0; i < 100; i++)
{
await Task.Delay(100);
cancellationToken.ThrowIfCancellationRequested();
}
}