【问题标题】:Which exception should be caught if a few were thrown in a stack trace?如果在堆栈跟踪中抛出了一些异常,应该捕获哪个异常?
【发布时间】:2021-07-27 13:06:11
【问题描述】:

这个堆栈跟踪被抛出:

System.Threading.Tasks.TaskCanceledException: The operation was canceled.
 ---> System.IO.IOException: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request..
 ---> System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.

我想准确地捕捉到这个异常,而不是一般的{Exception ex}

  • 我添加了哪一个?
  • 这里应该使用哪条规则?
  • 最后一个 (SocketException) 还是第一个 (TaskCanceledException) 应该被抓到?

谢谢!

【问题讨论】:

  • TaskCanceledException.

标签: c# exception


【解决方案1】:

在调用站点(引发异常的代码行),堆栈跟踪的顶部是捕获的异常。

如果你有代码:

try
{
    Foo();
}
catch (Exception e)
{

}

还有一个调用栈:

System.Threading.Tasks.TaskCanceledException:操作已取消。

---> System.IO.IOException: Unable to read data from the transport connection: I/O 操作由于线程退出或应用程序请求而中止..

---> System.Net.Sockets.SocketException (995):由于线程退出或应用程序请求,I/O 操作已中止。

然后您的catch 语句捕获了一个TaskCancelledException 和一个inner IOException,而后者又具有一个内部SocketException。异常层发生在Foo 执行时(直接或在Foo 调用的方法、属性等中)。

您可以修改您的块以仅捕获此异常:

try
{
    Foo();
}
catch (TaskCancelledException e)
{

}

与往常一样,您应该只捕获您可以处理的异常。如果包含try/catch 块的方法不知道如何重试/中止已取消的Task,那么您应该删除try/catch 块并让它抛出TaskCanceledException 以进一步处理堆栈。

如果您需要检查异常以查看您是否可以处理它,您可以修改您的代码以在不干扰堆栈跟踪的情况下获得访问权限,以防您必须rethrow它:

try
{
    Foo();
}
catch (TaskCanceledException e)
{
    if (e.Task.CheckSomething()) {
    
    }
    else {
        throw;
    }
}

从 C# 6.0 开始,这也可以使用 when 关键字来实现:

try
{
    Foo();
}
catch (TaskCanceledException e) when (e.Task.CheckSomething())
{

}

【讨论】:

    【解决方案2】:

    Exception ex 为您提供堆栈跟踪中的整个异常历史记录,您可以找出异常的来源。

    try
    {
        Foo();
    }
    catch (Exception ex)
    {
       var message = ex.Message;
    }
    

    【讨论】:

      【解决方案3】:

      问题是你应该抓住OperationCanceledException,而不是TaskCancelledException

      前者是base class for the latter one

      try
      {
          Foo();
      }
      catch (OperationCanceledException ocEx)
      {
        //TODO log and handle
      }
      

      Here are some test methods(由 Stephen Cleary 编写)证明您始终可以使用 OperationCanceledException 独立地捕获取消任务的方式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-08-24
        • 1970-01-01
        • 2010-10-10
        • 1970-01-01
        • 1970-01-01
        • 2011-01-05
        • 1970-01-01
        相关资源
        最近更新 更多