【问题标题】:finally block in c# [duplicate]最后在c#中阻塞[重复]
【发布时间】:2025-12-14 14:25:02
【问题描述】:

可能重复:
Finally Block Not Running??

我有一个关于 c# 中 finally 块的问题。 我写了一个小示例代码:

public class MyType
{
    public void foo()
    {
        try
        {
            Console.WriteLine("Throw NullReferenceException?");
            string s = Console.ReadLine();
            if (s == "Y")
                throw new NullReferenceException();
            else
                throw new ArgumentException();          
        }
        catch (NullReferenceException)
        {
            Console.WriteLine("NullReferenceException was caught!");
        }
        finally
        {
            Console.WriteLine("finally block");
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        MyType t = new MyType();
        t.foo();
    }
}

据我所知,finally 块假设确定性地运行,无论是否引发异常。 现在,如果用户输入“Y”——抛出 NullReferenceException,执行将移至 catch 时钟,然后移至 finally 块,如我所料。 但是如果输入是别的东西 - ArgumentException 被抛出。没有合适的 catch 块来捕获这个异常,所以我认为执行应该移动 finally 块 - 但它没有。谁能解释一下为什么?

谢谢大家:)

【问题讨论】:

  • 我试了下代码,按预期进入finally块
  • 你能澄清你的意思是什么'我认为执行应该移动 finally 块' - 我认为在这两种情况下控制都进入 finally - 对吗?
  • 是的,显然它确实进入了 finally 块,我错过了,因为调试器......:|

标签: c# exception-handling try-catch-finally


【解决方案1】:

您的调试器可能正在捕获 ArgumentException,因此它正在等待您在进入最后一个块之前“处理”它。在没有附加调试器的情况下运行您的代码(包括没有您的 JIT 调试器),它应该会命中您的 finally 块。

要禁用 JIT,请转到 选项 > 工具 > 调试 > 即时并取消选中 托管

要在没有附加调试器的情况下进行调试,请在 Visual Studio 中转到 Debug > Start without Debugging(或 CTRL + F5

在程序末尾放置一个 Console.ReadLine() 也很有帮助,以防止控制台在进入 finally 块后关闭。

class Program {
    static void Main(string[] args) {
        MyType t = new MyType();
        t.foo();
        Console.ReadLine();
    }
}

这是你应该得到的输出:


抛出 NullReferenceException?否

未处理的异常: System.ArgumentException:值确实 不在预期范围内。

在 ConsoleSandbox.MyType.foo() 中 P:\Documents\Sandbox\Console\Console\Consol e\Program.cs:第 17 行

在 ConsoleSandbox.Program.Main(String[] args) 在 P:\Documents\Sandbox\Console \Console\Console\Program.cs:第 31 行

终于屏蔽了

按任意键继续。 . .

【讨论】:

  • 嗯,你是对的。我不认为它与调试器有关,因为我在“异常”窗口中尝试了 CLR 运行时异常的“抛出”和“用户未处理”的所有 4 种组合。这不相关吗?我的意思是,如果我取消选中这些框,代码不应该不受干扰地运行吗?再次感谢您的时间。
  • 您指的是 [Debug > Exceptions] 选项;这与我上面提到的即时调试器选项不同。 JIT 调试器将捕获 UNHANDLED 异常,而您所指的异常选项是 Visual Studio 的附加调试器。
  • 只是想我会提到 Henk Holterman 也是正确的,并且使用 try/catch 围绕您的 t.foo() 调用将表明您的 finally 块确实被调用了-但这会改变您的情况因为您的 ArgumentException 成为已处理的异常,并且 JIT 调试器不会使它看起来像您的 finally 块不再被调用。这就是为什么我们应该始终处理我们的异常 =)
  • 我同意我的代码确实是一种不好的做法。它仅用于学习目的。
【解决方案2】:

您看到的是您的测试程序的产物。

如果你改变你的主要方法:

 static void Main(string[] args)
 {
    try
    {
        MyType t = new MyType();
        t.foo();
    }
    catch
    {
       // write something
    }
 }

那么您的foo() 将按预期运行。

如果没有* try/catch,您的整个程序将被中止。

【讨论】: