我正在为一位朋友检查一些代码,并说他在 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
  }
}
有帮助吗?

解决方案

简单的回答:是

其他提示

通常情况下,是的。最后部分保证执行发生的任何情况,包括异常或返回语句。此规则的一个例外是线程上发生的异步异常(OutOfMemoryException, StackOverflowException).

要了解有关异步异常和该情况下可靠代码的更多信息,请阅读 受限执行区域.

这里有一个小测试:

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

这MSDN引用

  

<强>最后用于保证不管代码语句块如何执行前述的尝试块的退出

通常是的,最终将运行。

对以下三种情况下,最终将 总是 运行:

  1. 没有例外情况发生
  2. 同步的例外 (例外情况发生在正常程序的流程)。
    这包括符合CLS例外情况,获得系统。例外和不符合CLS例外情况外,不得从系统。例外。非符合CLS的例外是自动包裹的RuntimeWrappedException.C#不能扔非CLS投诉的例外情况,但语言,例如C++可以。C#可以调用代码写在一语,可以把不符合CLS例外情况。
  3. 异步ThreadAbortException
    为。网2.0、ThreadAbortException将不再阻止一个最后运行。ThreadAbortException是现在升起来之前或之后的最后。最终会一直运行和不被中断由一个线程中止,只要的尝试是实际输入之前线的中断发生。

下面的方案,最后将不会运行:

异步StackOverflowException.
为。网2.0一堆溢出将导致该进程终止。最终会不可行,除非进一步的限制是适用于使最后一个核证的排减量(约束的执行地区)。核证的排减量不应当用一般用户代码。他们只应当使用至关重要的是,清洁代码一直运行--在所有的过程中被关闭在栈溢流无论如何和所有的托管对象,因此将清理的默认。因此,只有一个核证的排减量应该是相关的是对于资源分配之外的进程,例如,非托管处理。

通常,非托管的代码包括通过一些管理课之前被消耗的用户代码。该管理包装类将通常使用的一个SafeHandle包裹不受管处理。该SafeHandle实现了一个重要的终结,和释放方法是运行中的核证的排减量,以保证执行清理的编码。出于这个原因,你不应该看到的核证的排减量充斥通过用户代码。

所以事实上,最后没有上运行StackOverflowException应该没有影响到用户代码,由于该进程将终止。如果你有一些边的情况你需要清洗-一些不受管理的资源之外,一个SafeHandle或CriticalFinalizerObject,然后利用CER作为下;但请注意,这是不好实践--将不受管理的概念应被抽象到一个管理类别(es)和适当的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.
}

有对这个非常重要的例外,我还没有看到任何其他的答案中提到,并(在C#编程了18年后),我不相信,我不知道。

如果你扔或引发的异常的任何的排序里面你catch块(不只是奇怪StackOverflowExceptions和之流的东西),而且你没有内的另一个try/catch/finally块整个try/catch块,你finally块将不会执行。这是很容易证明 - 如果我还没有看到它自己,因为多久我读过,这只是很奇怪,微小的角落情况下,可能会导致一个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();
}

我敢肯定有一个原因,但它的怪异,它不是更广为人知。 (它指出例如href="https://stackoverflow.com/a/28483789/68231">,但在这个特殊的问题没有在任何地方。)

我意识到我迟到了,但在方案(从OP的例子不同),其中确实有异常抛出MSDN状态(的 https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ):的” 如果异常没有被捕获,执行的最后块取决于上的操作系统是否选择触发异常放松操作“。

在最后块仅保证到,如果一些其它的功能(如主)进一步调用堆栈向上捕捉异常执行。这个细节通常不是一个问题,因为所有的运行时环境(CLR和OS)C#程序上的免费资源最多运行一个进程拥有,当它退出(文件句柄等)。在某些情况下,它可能是至关重要的,但:要提交RESP数据库操作的一半正在进行中。放松;或一些远程连接,该连接可以不通过OS,然后阻止服务器自动关闭。

是的。这是在事实要点的最后发言。除非有catestrophic发生(在存储器、计算机拔出,等等。) 在最后发言总是应该以执行。

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

最后,不执行在时在线程运行Windows服务

最后惯于在运行的情况下如果从应用程序退出使用 System.exit(0);如在

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

结果将是公正: 尝试

这将保证该finally块中的代码将运行情景的99%,但是,觉得这个场景:你必须具有try-> finally块(无catch)一个线程,你会得到一个未处理该线程中的异常。在这种情况下,该线程将退出及其finally块将不被执行(该应用可以继续在这种情况下运行)

这情况是非常罕见的,但它只是表明,答案并不总是“是的”,这是大部分的时间“是”有时,在罕见的情况下,“否”。

最后块的主要目的是为执行无论是在其内部写入。它不应该依赖于在尝试或catch.However与System.Environment.Exit(1)应用程序将退出而不移动到下一行代码无论发生什么情况。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top