15

假设我在两个不同的程序集中有以下两个类:

//in assembly A
public class TypeA {
   // Constructor omitted
   public void MethodA
   {
     try {
       //do something
     }
     catch {
        throw;
     }
   }
}
//in assembly B
public class TypeB {
   public void MethodB
   {
     try {
       TypeA a = new TypeA();
       a.MethodA();
     }
     catch (Exception e)
       //Handle exception
     }
   }
}

在这种情况下,MethodA 中的 try-catch 只是提升了异常,但并没有真正处理它。在 MethodA 中使用 try-catch 有什么好处吗?换句话说,这种 try-catch 块和根本不使用它有区别吗?

4

11 回答 11

7

在您的示例中,这没有任何优势。但是在某些情况下,只需要冒泡一个特定的例外。

    public void Foo()
    {
        try
        {
            // Some service adapter code

            // A call to the service
        }
        catch (ServiceBoundaryException)
        {
            throw;
        }
        catch (Exception ex)
        {
            throw new AdapterBoundaryException("some message", ex);
        }
    }

这使您可以轻松识别发生异常的边界。在这种情况下,您需要确保仅针对特定于边界的代码引发边界异常。

于 2009-04-04T18:14:40.157 回答
3

使用您为 MethodA 编写的代码,没有区别。它所要做的就是消耗处理器周期。但是,如果有必须释放的资源,以这种方式编写代码可能会有优势。例如

Resource r = GetSomeResource();
try {
  // Do Something
} catch { 
  FreeSomeResource();
  throw;
}
FreeSomeResource();

然而,这样做并没有真正的意义。最好只使用 finally 块

于 2009-04-04T17:46:00.847 回答
3

是,有一点不同。当您捕获异常时,.NET 假定您将以某种方式处理它,堆栈将展开到执行捕获的函数。

如果您没有捕捉到它,它将最终成为一个未处理的异常,这将调用某种诊断(如调试器或异常记录器),完整的堆栈及其在实际故障点的状态将可供检查。

因此,如果您捕获然后重新抛出未在其他地方处理的异常,您就会抢夺诊断工具关于实际发生的事情的真正有用信息。

于 2009-04-04T17:51:53.813 回答
2

只是重新抛出是没有意义的——就像你什么都没做一样。

然而,当你实际做某事时它会变得很有用——最常见的事情是记录异常。您还可以更改班级的状态,无论如何。

于 2009-04-04T17:48:55.850 回答
2

照原样考虑,第一个选项似乎是个坏主意(或者那应该是“无用的”?)。但是,很少这样做。通常在两种情况下从 Catch 块中重新抛出异常:

一种。您想检查为数据生成的异常并有条件地将其冒泡到堆栈中。

try 
{
  //do something
}
catch (Exception ex)
{
  //Check ex for certain conditions.
  if (ex.Message = "Something bad")
    throw ex;
  else
    //Handle the exception here itself.
}

湾。组件内发生了不可接受的情况,需要将此信息传达给调用代码(通常通过附加一些其他有用的信息或将其完全包装在另一种异常类型中)。

try 
{
  //do something
}
catch (StackOverflowException ex)
{
    //Bubble up the exception to calling code 
    //by wrapping it up in a custom exception.
    throw new MyEuphemisticException(ex, "Something not-so-good just happened!");
}
于 2009-04-04T18:15:00.387 回答
1

永远不要做选项 A。正如 Anton 所说,它会占用堆栈跟踪。JaredPar 的示例也占用了堆栈跟踪。更好的解决方案是:

SomeType* pValue = GetValue();
try {
  // Do Something
} finally {
  delete pValue;
}

如果您在 C# 中有需要发布的内容,例如 FileStream,您有以下两个选择:

FileStream stream;
try
{
  stream = new FileStream("C:\\afile.txt");
  // do something with the stream
}
finally
{
  // Will always close the stream, even if there are an exception
  stream.Close(); 
}

或者更干净:

using (FileStream stream = new FileStream("c:\\afile.txt"))
{
  // do something with the stream
}

Using 语句将在完成或关闭异常时处理(并关闭)流。

于 2009-04-04T17:55:51.090 回答
1

当你接球和扔球时,它允许你throw在线上设置一个断点。

于 2009-04-04T17:58:36.090 回答
1

重新抛出异常可用于将其封装为通用异常,例如...考虑以下示例。

public class XmlException: Exception{
   ....
} 

public class XmlParser{
   public void Parse()
   {
      try{
          ....
      }
      catch(IOException ex)
      {
         throw new XmlException("IO Error while Parsing", ex );
      }
   }
}

这比对异常进行分类更有好处。这就是 aspx 文件处理程序和许多其他系统代码执行异常封装的方式,这决定了它们进入堆栈的方式及其逻辑流。

于 2009-04-04T17:58:56.793 回答
1

程序集 A - try catch - 块对我来说没有任何意义。我相信,如果您不打算处理异常,那么为什么要捕获这些异常..无论如何它都会被抛到一个新的水平。

但是,如果您正在创建中间层 API 或类似的东西并在该层中处理异常(并因此吃掉异常)没有意义,那么您可以抛出自己的层 ApplicationException。但肯定重新抛出相同的异常是没有意义的。

于 2009-04-04T19:47:16.283 回答
1

由于这些类位于 2 个不同的程序集中,您可能希望简单地捕获异常以记录它,然后将其扔回给调用者,以便它可以以它认为合适的方式处理它。throw 而不是 throw ex 将保留有关异常起源的上下文信息。当您的程序集是一个 API / 框架时,这可能很有用,在其中您不应该吞下异常,除非这样做有意义,但如果它被记录到 EventLog 中,则仍然有助于故障排除。

于 2009-04-04T21:58:19.570 回答
0

仅当您可以捕获可以在 MethodA() 中处理的特定异常(例如: logging )时,您才能在方法 A 中使用 try{} catch(ex){} 块。

另一种选择是使用 InnerException 属性链接异常并将其传递给调用者。这个想法不会杀死堆栈跟踪。

于 2016-02-05T09:10:45.270 回答