1.重新抛出异常时使用 throw代替 throw ex
如果要重新抛出异常,请直接使用 throw ; 因为在 catch 块中使用 throw ex 会丢失堆栈信息,throw 则不会。当然,如果对异常不做任何处理,只是简单地重新抛出,这种做法也是不可取的。
var client = new HttpClient(); string? result = null; try { result = await client.GetStringAsync(“http://www.baidu.com”); } catch(Exception ex) { //…一些处理异常的代码 // 直接使用 throw 而非 throw ex throw; } return result;
2.任何时候都不要吞没异常
有些初学者为了不让程序抛出异常,简单地用空 catch 语句吞没异常,这是典型的掩耳盗铃,非常坏的习惯!对于异常,要做相应的处理,至少也要重新抛出!
var client = new HttpClient(); string? result = null; try { result = await client.GetStringAsync(“http://www.baidu.com”); } catch { // 错误,坚决杜绝!简单粗暴地 // 吞没了异常,典型的掩耳盗铃 } return result;
3. 使用多个 catch 捕获不同类型的异常
var client = new HttpClient(); string? result = null; try { result = await client.GetStringAsync(“http://www.baidu.com”); } catch (HttpRequestException ex) { // 处理 HttpRequestException 的代码 } catch (TaskCanceledException ex) { // 处理 TaskCanceledException 的代码 result = null; }
4.使用过滤器更加精确地处理异常
var client = new HttpClient(); string? result = null; try { result = await client.GetStringAsync(“http://www.baidu.com”); } catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.Forbidden) { // 处理 403 错误的代码 } catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound) { // 处理 404 错误的代码 } return result;
5.使用日志记录异常
产生异常后,应使用日志系统记录异常。记录异常时,应提供具体有意义的说明,同时记录异常对象本身。
catch (FileNotFoundException ex) { // 不推荐,信息太过模糊 this.logger.logError(ex,”发生了一些错误”); // 不推荐,没有记录异常对象本身,丢失了堆栈等重要信息 this.logger.logError(“找不到请求的文件”); // 推荐,记录异常对象的同时提供有意义的说明 this.logger.LogError(ex, “找不到请求的文件”); }
6.尽量使用系统预先定义好的异常
因为系统预定义的异常知晓度高,语义明确,让第三方开发者更容易理解。比如:
- DivideByZeroException 零除异常
- ArgumentNullException,参数为空异常
- InvalidOperationException,非法操作异常
- IndexOutOfRangeException,索引超界异常
在绝大多数情况下,系统预定义的异常足够使用了。只有在系统预定义异常无法满足要求的时候,才考虑自定义异常。自定义的异常应主要集中在业务和领域层面,异常的命名应该遵循 XxxException 的形式。