Design patterns 捕获所有异常并根据分类将它们作为特定类型的异常重新抛出是一种好的做法吗?

Design patterns 捕获所有异常并根据分类将它们作为特定类型的异常重新抛出是一种好的做法吗?,design-patterns,language-agnostic,exception-handling,Design Patterns,Language Agnostic,Exception Handling,捕获所有异常并将其作为特定类型重新抛出(基本上是对从应用程序的特定部分(或服务)抛出的所有异常进行分类)是一种好的做法吗 比如: // This class is used to label all the exceptions occured on // Race Cars Service calls as RaceCarsServiceException public class RaceCarsServiceException : Exception { public class

捕获所有异常并将其作为特定类型重新抛出(基本上是对从应用程序的特定部分(或服务)抛出的所有异常进行分类)是一种好的做法吗

比如:

//  This class is used to label all the exceptions occured on 
// Race Cars Service calls as RaceCarsServiceException
public class RaceCarsServiceException : Exception
{

 public class RaceCarsServiceException (Exception e) 
               : base("Something went wrong!", e)
  {
     // Basically I assign the exception e as the inner exception 
     //by using the constructor method of Exception class
  }

}

public class RaceCarsService
{

// Some member fields, methods etc. here

 public double GetMaxSpeed(CarModel model)
 {
   try 
     {
       return (double)_carsWebService.GetMaxSpeed(model.ToString());
     }

   catch(Exception e)
     {
       throw new RaceCarsServiceException(e); // So all exceptions are rethrown 
                                           //as type of RaceCarsServiceException
     }
 }
}

此代码示例不重新显示异常,而是基于其他异常创建新异常

该代码将创建新的堆栈跟踪


这是一个巨大的争论问题

如果您正在抛出自定义异常,那么它们不应该像您的示例中那样直接从内部表达式映射。您应该执行某种条件检查,以区分您对特定自定义异常的特定需求与可能引发的各种异常

在我看来,如果在正确的地方适度地做,这会非常有益

在我构建的一个应用程序中,我们需要能够使用传入的参数回溯每个函数调用,以便我们能够识别导致异常的精确事件链

有时内部异常的粒度不够。或者您需要抛出一个异常,告诉您哪种进程失败了

例如,如果您的代码需要是事务性的,但可以跨多个服务工作,因此需要一些管理代码来处理事情,那么事务异常是合适的,事务回滚异常也是合适的(这通常意味着您处于痛苦的世界中)

然而,我知道有人强烈认为自定义异常是一件坏事。原因是它很容易被冲昏头脑,创造出太多对其他人来说毫无意义和无用的定制借口

我发现的一件事是,RecordDoesNotExist异常感觉上像是DAL异常,但实际上它是在业务逻辑中发生和处理最多的

因此,总而言之,我认为在正确的地方,适度地,有充分的理由,它们是一个好主意。但很容易得到一点他们

您应该始终将原始区域表达式传递到自定义异常中,并将其存储在那里。这会保留堆栈跟踪,并在抛出自定义堆栈跟踪的点的异常中存储堆栈跟踪

当审计它们是一项要求时,我使用自定义的expetions

编辑: 在其他答案中的链接之后,我必须说这是一篇关于Exceptions的伟大文章

与此有关的还有反模式

没有必要这样做(至少在您的示例中)。当试图调用可能抛出异常的方法时,分别处理不同类型的异常

try
{
    AMethodMayThrowExceptions();
}
catch (FileNotFoundException fileEx)
{
      //maybe create the file and retry
}
catch (TimeoutException timeoutEx)
{
      //maybe a retry after n seconds
}
catch (Exception ex)
{ 
      //other exceptions which I don't care
      //just a prompt of ex.Message or something
}
如果您使用单个
赛车服务异常
,将会发生什么情况

catch (RaceCarsServiceException ex)
{
    // now it's supposed to have a `ErrorCode` property, or an inner exception
    if (ex.ErrorCode == ErrorCode.File)
        //file exception, everything is the same with FileNotFoundException
    else ...
}

除了麻烦和可读性差的代码,你什么都没有

我不同意你的看法,因为你不知道他的方案是如何实施的。此外,我通常需要两个堆栈跟踪,因为有多种代码路径可以到达同一个位置,但我可以为这种情况创建更多从RaceCarsServiceException派生的异常类型。许多内置的.net异常不应该在用户代码中抛出,因为调用
Foo
可以区分两种非常不同的情况:(1)根据
Foo
的文档,发生的情况应引发
invalidoOperationException
;(2)
Foo
调用了一个抛出
invalidooperationexception
的方法,但
Foo
没有预料到这样的异常,也没有捕获到它。请注意,当
Foo
调用抛出异常的方法时,可能会出现条件#1。如何区分1和2?