为什么“使用”没有捕获块?

时间:2009-11-12 19:55:10

标签: c# language-features using using-statement

我理解“使用”的意思是保证调用对象的Dispose方法。但是如何处理“使用”语句中的异常呢?如果有异常,我需要在try catch中包装我的“using”语句。例如:


假设在使用参数

中创建对象时会产生异常
 try
 {
    // Exception in using parameter
    using (SqlConnection connection = new SqlConnection("LippertTheLeopard"))
    {
       connection.Open();
    }
 }
 catch (Exception ex)
 {

 }

或使用范围内的例外

 using (SqlConnection connection = new SqlConnection())
 {
    try
    {
       connection.Open();
    }
    catch (Exception ex)
    {

    }
 }

似乎我已经需要使用try catch处理异常,也许我应该只处理对象的处理。在这种情况下,“使用”声明似乎并没有帮助我。如何使用“using”语句正确处理异常?是否有更好的方法来解决这个问题?

 SqlConnection connection2 = null;
 try
 {
    connection2 = new SqlConnection("z");
    connection2.Open();
 }
 catch (Exception ex)
 {

 }
 finally
 {
    IDisposable disp = connection2 as IDisposable;
    if (disp != null)
    {
       disp.Dispose();
    }
 }

“使用”关键字语法可能会更加含糖......
这肯定会很高兴:

 using (SqlConnection connection = new SqlConnection())
 {
    connection.Open();
 }
 catch(Exception ex)
 {
   // What went wrong? Well at least connection is Disposed
 }

8 个答案:

答案 0 :(得分:27)

因为你会在一个不相关的关键字中“隐藏”额外的功能。

但是你总是这样写的

using (...) try
{
}
catch (...)
{
}

这种方式代表你的意图 - 一个也是一个尝试的使用陈述

答案 1 :(得分:12)

using与错误处理无关。它是“当你离开这个区块时调用Dispose”的简写。你的第二个代码示例是完全可以接受的......为什么搞乱哪些有效?

答案 2 :(得分:8)

using块只是try-finally块的语法糖。如果你需要一个catch子句,只需使用try-catch-finally:

SqlConnection connection;
try 
{
    connection = new SqlConnection();
    connection.Open();
}
catch(Exception ex)
{
    // handle
}
finally 
{
    if (connection != null)
    {
        connection.Dispose();
    }
}

是的,这比你的理论“使用 - 捕获”更多的代码;我判断语言开发人员并不认为这是一个非常重要的问题,我不能说我曾经感受到它的损失。

答案 3 :(得分:5)

我有过这个有用的地方。但更常见的是,当我想要这样做时,事实证明问题出在我的设计中;我正试图在错误的地方处理异常。

相反,我需要允许它进入下一个级别 - 在调用此代码的函数中处理它,而不是在那里。

答案 4 :(得分:2)

一个有趣的想法,但它会让以下有点混乱:

 using (SqlConnection connection = new SqlConnection())
 using (SqlCommand cmd = new SqlCommand())
 {
     connection.Open();
 }
 catch(Exception ex)
 {
     // Is connection valid? Is cmd valid?  how would you tell?
     // if the ctor of either throw do I get here?
 }

答案 5 :(得分:2)

我认为你在混淆问题。资源管理(即对象的处置)与异常处理完全分开。您在问题中描述的一对一映射只是一个非常特殊的情况。通常,异常处理不会在使用范围结束的同一位置发生。或者,您可能在使用块中有多个try-catch区域。或者......

答案 6 :(得分:0)

我建议您使用示例#1和#2组合。原因是你的using语句可以读取一个文件,例如,抛出一个异常(即File Not Found)。如果你没有捕获它,那么你有一个未处理的异常。将try catch块放在using块中只会捕获using语句执行后发生的异常。您的示例一和二的组合是最好的恕我直言。

答案 7 :(得分:0)

“using”语句的目的是确保在执行退出代码块时会发生某种类型的清理操作,无论该退出是通过直通,异常还是return 。当块通过任何这些方式退出时,它将在Dispose的参数上调用using。从某种意义上说,该块存在于为using参数指定的任何内容的好处,并且通常情况下该事件将不关心该块被退出的原因。

有几个不寻常的案例可能对这些条款有所帮助;他们的附加效用水平远远低于首先使用using所提供的水平(尽管可能比实施者认为适合提供的其他功能更好):

(1)对象的构造函数或工厂中有一个非常常见的模式,它封装了其他IDisposable个对象;如果构造函数或工厂通过异常退出,则封装的对象应为Dispose d,但如果它通过return退出,则不应该。try目前,此类行为必须通过catch / tryfinally / using与旗帜相结合来实施,但如果存在任何变化,恕我直言Dispose只会在通过异常退出时调用keep using,或者是using语句,它会使using语句所使用的临时空间无效以保存对象需要处理(因为yield return不能以标识符开头,这样的功能可能会以某种类似于finally)的方式添加。

(2)在某些情况下,如果Exception关键字扩展为接受null参数,将会很有帮助;它会保留导致被保护条款退出的异常(如果有的话),或using如果被保护的条款正常退出(通过返回或通过),并且interface IDisposeExOnly {void DisposeEx(Exception ex);}块可以使用Interface IDisposeEx : IDisposable, IDisposableExOnly {}DisposeEx()(在编译时,如果已实施则选择Dispose(),否则为null)。这可以允许基于事务的对象安全地支持自动提交(即,如果传入的异常为Dispose则执行提交,或者如果非空则则执行回滚),并且还允许在以下情况下改进日志记录Dispose由于受保护的子句中的问题而失败(正确的事情是{{1}}抛出一个异常,该异常封装了调用它时挂起的异常,以及发生的异常因此,目前还没有干净的方法来做到这一点。)

我不知道微软是否会添加这些功能;第一部分和第二部分将完全在语言层面处理。第二部分的后半部分将处于框架层面。