想法
我正在考虑在C# / .NET中使用回调函数代替抛出异常。
优缺点
优点:
- 没有像未经检查的异常控制流一样的隐藏goto
- 代码更加清晰,特别是涉及多个异常时
- 抛出的异常在方法签名中有所记录,调用者被迫考虑如何处理异常,但可以轻松地将应用程序范围的异常处理程序、"UnhandledExceptionHandler"或null传递给它们。因此,它们有点像"软"检查的异常,但更易于维护,因为异常可以通过重载方法后抛出,或者通过不再在异常处理程序上调用"handle"来移除异常)。
- 也适用于异步调用
- 异常处理程序可以处理在不同位置抛出的多个异常
- 明确指出哪些异常应该被处理。仍然可以使用普通方式抛出异常,例如不希望被处理的异常,如"NotImplementedException"。
缺点:
- 不符合C#和.NET的习惯用法
- 抛出方法必须立即返回返回值以中断控制流。如果返回类型是值类型,则会出现困难。
- ?(见下面的问题)
问题
我可能会忽略一些关键缺点,因为我想知道为什么这种方法没有被使用。我错过了哪些缺点?
示例:
与其这样写:
void ThrowingMethod() {
throw new Exception();
}
并且
void CatchingMethod() {
try {
ThrowingMethod();
} catch(Exception e) {
//handle exception
}
}
我会去做
void ThrowingMethod(ExceptionHandler exceptionHandler) {
exceptionHandler.handle(new Exception());
}
void CatchingMethod() {
ThrowingMethod(exception => */ handle exception */ );
}
使用
delegate void ExceptionHandler(Exception exception);
在某个地方定义了一个方法,"handle(...)" 是一个扩展方法,用于检查空值、检索堆栈跟踪,并在抛出异常时没有异常处理程序时可能抛出 "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);
}
Example with methods that return values
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 */ );
}
使用
delegate TResult ExceptionHandler<TResult>(Exception exception);
Exception
情况下,您可以抛出IOError
并在远处捕获它,给用户一个一般性错误,回溯堆栈,释放资源并完成。 - Bart Friederichsif (h==null) { do something; } else { safe to call h.something() }
。 - Ali