【发布时间】:2012-09-19 23:28:33
【问题描述】:
将任务用于需要取消的大型/长时间运行的工作负载时,我经常使用与此类似的模板来执行任务:
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;
}
}
罢工>
即,将某种排除列表应用于捕获,但没有当前不可能的语言支持(@eric-lippert:c# vNext 功能:))。
另一种方法是通过延续:
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 吗?
【问题讨论】:
-
我使用了一个解决方案,其中日志框架对某些异常执行不同的操作。即忽略 OperationCancelledException,展平 AggregateException,仅记录 InvalidOperationException 的 innerException 等
标签: c# exception task-parallel-library