使用回调而不是抛出异常?

6 .net c# design-patterns

理念

我正在考虑使用回调而不是在C#/ .NET中抛出异常.

优点和缺点

优点是

  • 没有隐藏的goto像未经检查的异常的控制流
  • 更清晰的代码,特别是如果涉及多个例外
  • 抛出的异常记录在方法签名中,并且调用者被迫考虑处理异常,但可以轻松地传递应用程序范围的异常处理程序,"UnhandledExceptionHandler"或null.因此它们有点像"软"检查异常但更易于维护,因为异常可以通过重载方法抛出,或者异常可以通过不再在异常处理程序上调用"句柄"来消除.
  • 适用于异步调用
  • 异常处理程序可以处理在不同位置抛出的几个异常
  • 明确应该处理哪些例外.普通方式抛出异常仍可用于您不希望像"NotImplementedException"那样处理的异常.

缺点是

  • 不是C#和.NET的惯用语
  • throw方法必须通过立即返回一个返回值来中断控制流程.如果返回类型是值类型,则这很困难.
  • ?(见下面的问题)

我可能错过了一些关键的缺点,因为我想知道为什么不使用它.我错过了什么缺点?

例:

代替

void ThrowingMethod() {
    throw new Exception();
}
Run Code Online (Sandbox Code Playgroud)

void CatchingMethod() {
    try {
         ThrowingMethod();
    } catch(Exception e) {
         //handle exception
    }
}
Run Code Online (Sandbox Code Playgroud)

我会做

void ThrowingMethod(ExceptionHandler exceptionHandler) {
    exceptionHandler.handle(new Exception());
}

void CatchingMethod() {
     ThrowingMethod(exception => */ handle exception */ );
}
Run Code Online (Sandbox Code Playgroud)

delegate void ExceptionHandler(Exception exception);
Run Code Online (Sandbox Code Playgroud)

在某处定义并且"handle(...)"是一个检查null的扩展方法,检索堆栈跟踪,如果在抛出异常时根本没有异常处理程序,则可能抛出"UnhandledException".


在之前未抛出异常的方法中抛出异常的示例

void UsedToNotThrowButNowThrowing() {
   UsedToNotThrowButNowThrowing(null);
}

//overloads existing method that did not throw to now throw
void UsedToNotThrowButNowThrowing(ExceptionHandler exceptionHandler) {
    //extension method "handle" throws an UnhandledException if the handler is null
    exceptionHandler.handle(exceptionHandler);
}
Run Code Online (Sandbox Code Playgroud)

返回值的方法示例

TResult ThrowingMethod(ExceptionHandler<TResult> exceptionHandler) {
        //code before exception
        return exceptionHandler.handle(new Exception()); //return to interrupt execution
        //code after exception
    }

TResult CatchingMethod() {
     return ThrowingMethod(exception => */ handle exception and return value */ );
}
Run Code Online (Sandbox Code Playgroud)

delegate TResult ExceptionHandler<TResult>(Exception exception);
Run Code Online (Sandbox Code Playgroud)

mun*_*esh 0

一方面,您将需要将这些处理程序传递给应用程序中的几乎每个方法,从而产生开销。这是一个非常重量级的依赖项,也是在构建应用程序之前做出的生死攸关的决定。

其次,存在处理系统引发的异常和来自第三方程序集的其他异常的问题。

第三,异常意味着在抛出时停止程序的执行,因为它确实是“异常”,而不仅仅是可以处理的错误,允许继续执行。