我有不同的类(实现接口),其中一种方法是执行异步数据库搜索:
public async void SearchAsync(CancellationToken ct)
{
await Task.Run(() => {Find(); }, ct);
}
private void Find()
{
//do db search here...
}
当打开表单时,会执行后台异步搜索以加快用户输入,所以我所做的是:
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
try
{
//Get list of items that will perform async search...
//var results = ...
//Do an async search
Task task = Task.Factory.StartNew(() =>
{
foreach (var item in results)
{
item.SearchAsync(cts.Token);
}
}, cts.Token);
}
catch (OperationCanceledException)
{ }
}
如果用户关闭表单而任务仍在执行,我会这样做:
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (cts != null)
{
cts.Cancel();
}
}
首先,上面是执行异步操作的正确方法吗?
其次,当我在任务仍未完成时关闭表单时,代码永远不会到达OperationCancelException。可能是上述实施不正确吗?
答案 0 :(得分:3)
有几点要注意。首先,您正在使用"async over sync"反模式,应该强烈避免。你也传递了一个CancellationToken
但实际上从未监视过它。如果您的方法是同步的,那么在执行时您无法真正监视它,您可以做的最好是在执行CancellationToken
的每次迭代之前监视Search
:
public void Search()
{
Find();
}
protected override async void OnShown(EventArgs e)
{
base.OnShown(e);
try
{
await Task.Run(() =>
{
foreach (var item in results)
{
cts.Token.ThrowIfCancellationRequested();
item.Search();
}
}, cts.Token);
}
catch (OperationCanceledException)
{ }
}
然后你取消:
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (cts != null)
{
cts.Cancel();
}
}