CodeGym /课程 /C# SELF /finally块和throw操作符

finally块和throw操作符

C# SELF
第 13 级 , 课程 2
可用

1. 认识finally

清理和释放资源

想象一下:你在化学实验室里做实验,等一切结束(哪怕你炸了几个烧瓶),你还是得收拾实验台、冲洗化学品、关灯。finally块就是干这个用的——它总会在trycatch之后执行,不管有没有异常发生。


try
{
    // 这里写“危险”代码,可能会抛出异常
}
catch
{
    // 这里捕获并处理异常
}
finally
{
    // 这段代码总会执行,不管有没有异常
}
C#里的try-catch-finally结构

为什么要这样? 首先是为了保证资源一定被释放:比如关闭文件、断开数据库连接、解锁机房的门……如果没有finally,一旦出错,有些资源可能就“卡住”了——这就很麻烦。比如文件被锁住,连管理员都打不开。

为啥不能都写在catch里?

我们能不能直接在catch里释放资源?理论上可以。但如果一切顺利,catch根本不会执行。如果你想确保资源总是被释放,就得用finally

现实开发中经常遇到这种情况:不管成功还是失败——都得收拾残局。这就是finally存在的意义。

2. finally块的特点

什么时候finally不会执行?

这是个小陷阱!finally几乎总是会执行。就算在try里有return(提前返回方法),或者抛出新异常,finally还是会被执行


static void Test()
{
    try
    {
        Console.WriteLine("到return之前");
        return;
    }
    finally
    {
        Console.WriteLine("finally还是会执行!");
    }
}

//调用Test()
Test();
输出:

// 到return之前
// finally还是会执行!
    

不过,如果你的程序突然“崩溃”了(比如电脑断电、进程被杀掉或者CLR挂了),finally就不会执行了。这种情况也没办法。

finally操作符和调用栈

调用栈我们下节课会详细讲,这里简单说下:它就像一摞被调用的方法,程序会“往下走”,直到找到合适的catch

还有个重点:如果try里抛出异常,而catch没接住(比如没有合适的处理器),程序就会离开当前方法,继续沿着调用栈往上找,直到遇到合适的catch。但在这之前,每一层都会先执行finally块。

这样就能保证资源总是被正确释放,就算遇到奇怪的错误也不怕。

3. throw操作符:怎么自己抛异常

throw是啥,有啥用

有时候光捕获异常还不够——你可能需要自己造一个错误“扔”出去。这就得用throw操作符。


throw new Exception("这是我的专属错误!");
创建并抛出自定义异常

throw就是在跟CLR说:“我发现了大问题,扔个Exception出去,后面谁调用这段代码谁负责处理。”

throw不创建新异常的用法

你可以在catch块里用throw;,把刚刚捕获的异常再抛出去——比如你只处理了一部分错误,剩下的想让上层代码继续处理。


try
{
    DangerousOperation();
}
catch (Exception ex)
{
    LogError(ex);
    throw; // 再次抛出当前异常,调用栈信息会保留
}
保留调用栈信息的再次抛出异常

如果你写成throw ex;,调用栈信息就丢了——这是个坏习惯。

4. finallythrow一起用会怎样?

抛异常时finally也会执行

来看看:如果在trythrow了异常,同时又有finally,会发生什么?


try
{
    Console.WriteLine("抛异常前...");
    throw new Exception("try块里的错误!");
}
catch
{
    Console.WriteLine("Catch捕获了错误。");
}
finally
{
    Console.WriteLine("Finally执行了。");
}
抛异常时finally依然会执行

结果如下:


抛异常前...
Catch捕获了错误。
Finally执行了。

如果没有合适的catchfinally还是会在程序崩溃前执行。

细节:如果finally里也throw会怎样?

如果在finally里也抛出throw,那这个异常会覆盖之前的异常。也就是说,try/catch里的异常信息就丢了。所以一般不建议在finally里再抛异常,尤其是前面已经有异常的时候。


try
{
    throw new Exception("try里的错误");
}
finally
{
    throw new Exception("finally里的错误");
}
// 结果:外面只会看到"finally里的错误"
finally抛出的异常会覆盖之前的异常

5. 实用建议和常见错误

新手最容易忘的点

  • 释放资源时没用finally块,只靠catch
  • 把可能抛新异常的代码写进finally——这样容易出意外。
  • 忘了returntry里不会“跳过”finally——它总会执行。

finally的替代方案:怎么选?

有了using结构(我们后面会详细讲),释放资源更方便了,但其实using底层还是用的finally。遇到特殊情况(比如解锁、发错误通知),还是得用finally

面试官为啥喜欢考finally

每个写过高并发服务器的面试官都爱问finally。常见问题:“如果try里有returnfinally里有throw会怎样?”或者“异常时资源一定能释放吗?”现在你不仅能答出来,还能讲明白原理。你能说清楚finally怎么用、为啥用、啥时候用——没有它,靠谱的代码根本写不出来。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION