10

我理解“使用”的目的是保证调用对象的 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
 }
4

8 回答 8

27

因为您将在不相关的关键字中“隐藏”额外的功能。

但是你总是可以这样写

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

这样,这条线就代表了你的意图——一个 using 语句,也是一个 try

于 2009-11-12T20:01:00.930 回答
12

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

于 2009-11-12T19:58:45.313 回答
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();
    }
}

是的,这比您理论上的“using-catch”代码更多;我判断语言开发人员并不认为这是一个非常重要的优先事项,我不能说我曾经感受到它的损失。

于 2009-11-12T20:00:28.247 回答
5

我有过这很有用的地方。但更多时候,当我想这样做时,结果发现问题出在我的设计中。我试图在错误的地方处理异常。

相反,我需要让它更上一层楼——在调用此代码的函数中处理它,而不是直接在那里处理。

于 2009-11-12T20:00:59.400 回答
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?
 }
于 2009-11-12T19:59:39.247 回答
2

在我看来,你正在混合担忧。资源管理(即对象的处置)与异常处理完全分离。您在问题中描述的一对一映射只是一个非常特殊的情况。通常异常处理不会在 using 范围结束时发生在同一个地方。或者您可能在 using 块中有多个 try-catch 区域。或者 ...

于 2009-11-12T20:02:58.087 回答
0

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

于 2009-11-12T20:05:38.440 回答
0

“using”语句的目的是确保在执行退出代码块时会发生某种类型的清理操作,无论该退出是通过失败、异常还是return. 当块通过任何这些方式退出时,它将Dispose调用using. 从某种意义上说,该块的存在是为了任何被指定为using参数的东西的好处,并且通常那个东西不会关心为什么退出该块。

有几个不寻常的情况,规定可能会有所帮助;它们的附加效用水平将远低于using最初提供的水平(尽管可以说比实施者认为适合提供的其他一些功能更好):

(1) 对象的构造函数或工厂封装其他对象有一种很常见的模式IDisposable;如果构造函数或工厂通过异常退出,则封装的对象应为Disposed,但如果通过异常退出,return则不应。目前,这种行为必须通过try/catch或通过将try/finally与标志组合来实现,但恕我直言,如果有一个变体using只会Dispose在它通过异常退出时调用,或者有一个keep using语句将使语句临时使用using来保存需要处理的对象(因为using前面不能有标识符,所以可以以某种类似于 的方式添加这样的特征yield return)。

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

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

于 2012-07-30T15:08:13.843 回答