Hi I have a listbox Whenever a user selects an item a request is sent to the web Now I want to cancel the previous operation when the user selected the item and then start the new operation.
I used the following codes to do this, I wanted to know if these codes work well. Or should I try another way?
private CancellationTokenSource ts = new CancellationTokenSource();
private async void Subf2mCore(CancellationToken ct)
{
HtmlDocument doc = await web.LoadFromWebAsync(url);
...
foreach (var node in doc)
{
if (!ct.IsCancellationRequested)
{
....
}
}
}
and i run func this way
ts?.Cancel();
ts = new CancellationTokenSource();
Subf2mCore(ts.Token);
Technically, you can put it like this, but look: you fire and forget, let return Task
for caller to know if Subf2mCore
has been completed, failed or cancelled:
private async Task Subf2mCore(CancellationToken ct)
{
HtmlDocument doc = await web.LoadFromWebAsync(url);
...
foreach (var node in doc)
{
// Often we cancel by throwing exception:
// it's easy to detect that the task is cancelled by catching this exception
// ct.ThrowIfCancellationRequested();
// You prefer to cancel manually:
// your cancellation can be silent (no exceptions) but it'll be
// difficult for caller to detect if task completed or not
// (partially completed and cancelled)
if (!ct.IsCancellationRequested)
{
....
}
}
}
// If we don't want to cancel
private async Task Subf2mCore() => Subf2mCore(CancellationToken.None);
Usage: do not forget to Dispose
CancellationTokenSource
instance:
using (CancellationTokenSource ts = new CancellationTokenSource()) {
...
await Subf2mCore(ts.Token);
...
}
Edit: if you want to cancel from outside:
private CancellationTokenSource ts = null;
...
using (CancellationTokenSource _ts = new CancellationTokenSource()) {
// previous task (if any) cancellation
if (null != ts)
ts.Cancel();
// let cancel from outside
ts = _ts;
try {
...
await Subf2mCore(_ts.Token);
...
}
finally {
// task completed, we can't cancel it any more
ts = null;
}
}