在将任务用于需要能够取消的大型/长时间运行的工作负载时,我经常使用与此类似的模板来执行任务的操作:
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
现在关闭了“用户未处理中断” )。OperationCanceledException
更新:现在是 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
}
但我真的不喜欢这样,因为从技术上讲,异常可能有多个内部异常,并且在记录异常时没有像在第一个示例中那样多的上下文(如果我做的不仅仅是记录它)。
我知道这是一个风格问题,但想知道是否有人有更好的建议?
我只需要坚持示例1吗?