首页 文章

如果我在Try块中返回一个值,那么finally语句中的代码会触发吗?

提问于
浏览
207

我正在为一位朋友审查一些代码,并说他在try-finally块中使用了一个return语句 . 即使try块的其余部分没有,Finally节中的代码是否仍会触发?

例:

public bool someMethod()
{
  try
  {
    return true;
    throw new Exception("test"); // doesn't seem to get executed
  }
  finally
  {
    //code in question
  }
}

13 回答

  • 3

    简单回答:是的 .

  • 134

    是 . 这实际上是最终陈述的要点 . 除非发生某些事情(内存不足,计算机未插入等),否则应始终执行finally语句 .

  • 192

    如果你使用System.exit(0)退出应用程序,最后不会运行;如在

    try
    {
        System.out.println("try");
        System.exit(0);
    }
    finally
    {
       System.out.println("finally");
    }
    

    结果就是:试试

  • 0

    finally块的主要目的是执行在其中写入的任何内容 . 它不应该依赖于try或catch中发生的任何事情 . 但是对于System.Environment.Exit(1),应用程序将退出而不移动到下一行代码 .

  • 0

    它也不会触发未捕获的异常并在Windows服务中托管的线程中运行

    Finally is not executed when in a Thread running in a Windows Service

  • 2

    有一个非常重要的例外,我在其他任何答案中都没有提到过,而且(在用C#编程18年后)我无法相信我不知道 .

    如果你在 catch 块中抛出或触发任何类型的异常(不只是奇怪的 StackOverflowExceptions 和那种类似的东西),并且你没有整个 try/catch/finally 块在另一个 try/catch 块中,你的 finally 块赢了't execute. This is easily demonstrated - and if I hadn' t我自己看到了鉴于我经常只是非常奇怪的小角落情况会导致 finally 块无法执行,我不会相信它 .

    static void Main(string[] args)
    {
        Console.WriteLine("Beginning demo of how finally clause doesn't get executed");
        try
        {
            Console.WriteLine("Inside try but before exception.");
            throw new Exception("Exception #1");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Inside catch for the exception '{ex.Message}' (before throwing another exception).");
            throw;
        }
        finally
        {
            Console.WriteLine("This never gets executed, and that seems very, very wrong.");
        }
    
        Console.WriteLine("This never gets executed, but I wasn't expecting it to."); 
        Console.ReadLine();
    }
    

    我这是一个原因,但它并没有广为人知 . (例如,它被注意到here,但在这个特定问题中没有任何地方 . )

  • 6

    我意识到我的例子)确实抛出异常MSDN状态(https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx):_ "If the exception is not caught, execution of the finally block depends 关于操作系统是否选择触发异常展开操作 . “

    如果调用堆栈中的某些其他函数(例如Main)捕获异常,则仅保证finally块执行 . 这个细节通常不是问题,因为所有运行时环境(CLR和OS)C#程序都在进程退出时拥有的大多数资源(文件句柄等)上运行 . 在某些情况下,它可能是至关重要的:正在进行的数据库操作正在进行中,您要提交resp . 放松;或某些远程连接,可能无法由操作系统自动关闭,然后阻止服务器 .

  • 33

    这是一个小测试:

    class Class1
    {
        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("before");
            Console.WriteLine(test());
            Console.WriteLine("after");
        }
    
        static string test()
        {
            try
            {
                return "return";
            }
            finally
            {
                Console.WriteLine("finally");
            }
        }
    }
    

    结果是:

    before
    finally
    return
    after
    
  • 234

    一般是的,终于会运行 .

    对于以下三种情况,最终将始终运行:

    • No exceptions occur

    • Synchronous exceptions (正常程序流程中发生的异常) .
      这包括从System.Exception和非CLS兼容的异常派生的CLS兼容异常,这些异常不是从System.Exception派生的 . RuntimeWrappedException会自动包装非CLS兼容的异常 . C#不能抛出非CLS投诉异常,但C语言可以 . C#可以调用用可以抛出非CLS兼容异常的语言编写的代码 .

    • Asynchronous ThreadAbortException
      从.NET 2.0开始,ThreadAbortException将不再阻止finally运行 . ThreadAbortException现在被提升到finally之前或之后 . 最终将始终运行并且不会被线程中止中断,只要在线程中止发生之前实际输入了try .

    以下场景,终于不会运行:

    Asynchronous StackOverflowException.
    从.NET 2.0开始,堆栈溢出将导致进程终止 . 除非应用进一步约束以使最终成为CER(约束执行区域),否则最终将不会运行 . CER不应用于一般用户代码 . 它们只应在清理代码始终运行至关重要的地方使用 - 无论如何都要关闭堆栈溢出,因此默认情况下将清理所有托管对象 . 因此,CER应该与之相关的唯一地方是在流程外部分配的资源,例如,非托管句柄 .

    通常,非托管代码在被用户代码使用之前由某个托管类包装 . 托管包装器类通常会使用SafeHandle来包装非托管句柄 . SafeHandle实现了一个关键的终结器,以及一个在CER中运行的Release方法,以保证执行清理代码 . 因此,您不应该看到CERs遍布整个用户代码 .

    因此,最终不会在StackOverflowException上运行的事实应该对用户代码没有影响,因为该进程无论如何都将终止 . 如果你有一些边缘情况,你需要清理一些非托管资源,在SafeHandle或CriticalFinalizerObject之外,那么使用CER如下;但请注意,这是不好的做法 - 非托管概念应抽象为a托管类和适当的SafeHandle(s)设计 .

    例如 . ,

    // No code can appear after this line, before the try
    RuntimeHelpers.PrepareConstrainedRegions();
    try
    { 
        // This is *NOT* a CER
    }
    finally
    {
        // This is a CER; guaranteed to run, if the try was entered, 
        // even if a StackOverflowException occurs.
    }
    
  • 2

    99%的场景将保证 finally 块中的代码将运行,但是,请考虑这种情况:你有一个具有 try - > finally 块(没有 catch )的线程,并且你得到一个未处理的异常线 . 在这种情况下,线程将退出并且不会执行其 finally 块(在这种情况下应用程序可以继续运行)

    这种情况非常罕见,但只是表明答案并非总是“是”,大部分时间都是“是”,有时候,在极少数条件下,“不” .

  • 9

    是的,最后致电 .

    public static bool someMethod()
        {
            try
            {
    
                return true;
                throw new Exception("test"); // doesn't seem to get executed
            }
            finally
            {
                //code in question
            }
        }
    
  • 18

    引自MSDN

    最后用于保证语句代码块的执行,而不管前面的try块是如何退出的 .

  • 0

    通常,是的 . finally部分保证执行包括异常或return语句在内的任何操作 . 此规则的一个例外是线程上发生异步异常( OutOfMemoryExceptionStackOverflowException ) .

    要了解有关异步异常和可靠代码的更多信息,请阅读constrained execution regions .

相关问题