不该写空 catch 块,因其掩盖异常导致问题无法排查;async 中需在 await 处捕获异常;优先用 using 而非 finally 管理 IDisposable 资源;全局异常处理器不能替代分层 try-catch。

try-catch 里该不该写空的 catch 块
不该。空 catch 块是健壮性最大的反模式——它让异常静默消失,问题现场彻底丢失。
常见错误现象:try { DoSomething(); } catch { } 看似“防崩”,实则掩盖了 NullReferenceException、IOException 等真实故障,后续逻辑错乱却无从排查。
- 只捕获明确知道如何处理的异常类型,比如
catch (FileNotFoundException ex) - 对未知异常至少要记录日志:
catch (Exception ex) { logger.Error(ex); throw; }(注意throw;而非throw ex;,保留原始堆栈) - 绝不在生产代码中出现
catch {}或catch (Exception) {}
async 方法里异常怎么正确传播
await 后的异常不会被同步 try-catch 捕获,必须在 await 表达式所在层级处理,否则会“掉进 Task 的黑洞”。
使用场景:调用 HttpClient.GetAsync()、File.ReadAllLinesAsync() 等异步 I/O 操作时。
- 错误写法:
try { var t = GetDataAsync(); } catch { }—— 这里根本捕不到异常,t是未完成的Task - 正确写法:
try { var result = await GetDataAsync(); } catch (HttpRequestException ex) { ... } - 若需在非 async 方法中处理,必须用
.GetAwaiter().GetResult()(仅限极少数同步上下文场景),但会阻塞线程,且异常包装为AggregateException
什么时候该用 finally,什么时候该用 using
finally 是清理动作的兜底保障;using 是资源确定性释放的语法糖,两者目标一致但适用粒度不同。
性能与兼容性影响:.NET 6+ 中 using 声明(using var fs = new FileStream(...);)编译后等效于 try/finally,无额外开销;但 .NET Framework 4.0 之前不支持该语法。
- 优先用
using处理实现了IDisposable的对象,如FileStream、SqlConnection、HttpClient - 当清理逻辑复杂(比如要重试释放、或需检查状态后再释放),才显式写
finally - 不要在
finally里抛异常——它会覆盖原异常;若必须报错,改用日志记录
全局异常处理器能替代 try-catch 吗
不能。全局处理器(如 AppDomain.UnhandledException、WebHostBuilder.UseExceptionHandler)只是最后一道防线,不是错误处理策略。
容易踩的坑:有人把所有业务异常都扔给全局 handler,结果无法区分可恢复错误(如网络超时)和不可恢复错误(如配置缺失),也无法做针对性重试或降级。
- 全局 handler 只用于记录未捕获异常 + 返回友好提示(如 HTTP 500 页面),绝不用于业务逻辑分支
- 数据库连接失败应捕获
SqlException并重试;文件不存在应捕获FileNotFoundException并走默认路径 - ASP.NET Core 中,
UseExceptionHandler不会捕获TaskCanceledException(请求取消),这类需单独在 controller 层处理
真正难的不是加多少 try,而是判断哪一层该吞、哪一层该抛、哪一层该转成用户能懂的提示——边界模糊时,异常类型比错误消息更可靠。


















