当我需要取消大型/长时间运行的工作负载时,我经常使用类似于以下模板的任务执行操作:
public void DoWork(CancellationToken cancelToken)
{
try
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
Log.Exception(ex);
throw;
}
}
OperationCanceledException
不应该被记录为错误,但如果任务要转换为被取消状态,则不得被忽略。除此之外的任何其他异常均无需在此方法的范围之外处理。这种做法始终感觉有些笨拙,而 Visual Studio 默认情况下会在
OperationCanceledException
的 throw 处中断(尽管我现在已将“用户未处理的中断”关闭了,因为我使用了这种模式)。更新: 现在是 2021 年,C#9 给了我一直想要的语法:
public void DoWork(CancellationToken cancelToken)
{
try
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
Log.Exception(ex);
throw;
}
}
public void DoWork(CancellationToken cancelToken)
{
try
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}
catch (Exception ex) exclude (OperationCanceledException)
{
Log.Exception(ex);
throw;
}
}
public void StartWork()
{
Task.Factory.StartNew(() => DoWork(cancellationSource.Token), cancellationSource.Token)
.ContinueWith(t => Log.Exception(t.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
}
public void DoWork(CancellationToken cancelToken)
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}
但我并不太喜欢这种方式,因为异常技术上可能会有多个内部异常,而在记录异常时,您没有第一个示例中那么多的上下文信息(如果我不仅仅是记录它)。
我知道这有点像风格问题,但想知道是否有更好的建议?
我只能坚持使用第一种方案吗?