附加Visual Studio调试器时未处理异常导致finally块不执行的问题
看起来你有一个简单的.NET Framework控制台项目,先把你的项目结构和配置整理清楚:
项目文件结构
C:\work\PassThruExc> tree /f Folder PATH listing for volume OSDisk Volume serial number is F6C4-7BEF C:. │ PassThruExc.csproj │ PassThruExc.sln │ Program.cs │ └───Properties launchSettings.json
项目配置(PassThruExc.csproj)
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net472</TargetFramework> </PropertyGroup> </Project>
问题分析
你遇到的核心问题应该是:当你在Visual Studio中附加调试器运行程序时,如果代码抛出了未处理的异常,调试器会立即在异常抛出的位置中断,这时候finally块还没来得及执行——因为异常还没进入完整的处理流程,调试器就暂停了程序的执行。如果这时候你直接终止调试会话,finally块自然不会被执行;即使你继续运行,也只有当异常被允许继续传播时,finally块才会在程序崩溃前执行。
解决办法
这里有几个可行的方案来确保finally块能被执行,或者调整调试行为:
捕获并处理顶级异常
在你的Main方法外层添加异常捕获,确保异常被处理,这样finally块就能正常执行:static void Main(string[] args) { try { // 你的业务代码,可能抛出异常的部分 throw new Exception("未处理的异常"); } catch (Exception ex) { // 处理异常,比如记录日志 Console.WriteLine($"捕获到异常: {ex.Message}"); } finally { // 这里的代码一定会执行 Console.WriteLine("finally块执行"); } }调整调试器的异常中断行为
默认情况下,Visual Studio会在未处理的异常抛出时立即中断。你可以修改这个设置:- 打开
调试->Windows->异常设置(快捷键:Ctrl+Alt+E) - 找到
Common Language Runtime Exceptions,取消勾选“抛出”列的复选框(只保留“用户未处理”的勾选)
这样调试器只会在异常真的没有被任何代码处理时才中断,而finally块会先执行完毕。
- 打开
处理AppDomain级别的未处理异常
对于控制台应用,你可以注册AppDomain.CurrentDomain.UnhandledException事件,这样即使有未处理的异常,也能在程序终止前执行必要的清理逻辑(包括finally块):static void Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += (sender, e) => { Console.WriteLine($"捕获到未处理的顶级异常: {e.ExceptionObject}"); // 这里可以添加额外的清理逻辑 }; try { throw new Exception("未处理的异常"); } finally { Console.WriteLine("finally块执行"); } }注意:注册这个事件后,即使异常未被处理,
finally块依然会执行,然后程序才会触发这个事件并终止。
关键提醒
如果你在调试器中断后直接点击“停止调试”(Shift+F5),那么进程会被强制终止,任何未执行的代码(包括finally块)都不会运行——这是正常的行为,因为进程被强行结束了,没有机会执行后续代码。只有让程序继续执行(F5),直到自然终止,finally块才会执行。
内容来源于stack exchange

