代码之家  ›  专栏  ›  技术社区  ›  SwDevMan81 Chris Barlow

为什么“使用”没有catch块?

  •  10
  • SwDevMan81 Chris Barlow  · 技术社区  · 15 年前

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


    假设在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”语句似乎对我毫无帮助。如何正确处理带有“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 回复  |  直到 12 年前
        1
  •  5
  •   Joel Coehoorn    15 年前

    我曾经有过这样有用的地方。但更常见的是,当我想这样做时,发现问题出在我的设计中;我试图在错误的地方处理异常。

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

        2
  •  27
  •   Kevin Laity    15 年前

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

    但是你可以一直这样写

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

    这样,行就代表了您的意图——一个使用语句,也是一个尝试

        3
  •  12
  •   Dave Swersky    15 年前

    using 与错误处理无关。它是“离开此块时调用Dispose”的简写。您的第二个代码示例完全可以接受…为什么要搞得一团糟?

        4
  •  8
  •   Michael Petrotta user3140870    15 年前

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

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

    是的,这比你理论上的“使用catch”更多的是代码;我判断语言开发人员没有把这当作一个非常高的优先级,我不能说我从未感受过它的损失。

        5
  •  2
  •   csharptest.net    15 年前

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

     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?
     }
    
        6
  •  2
  •   Achim    15 年前

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

        7
  •  0
  •   user195488    15 年前

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

        8
  •  0
  •   supercat    12 年前

    “using”语句的目的是确保当执行退出代码块时,无论该退出是通过fall-through、异常还是 return . 当模块通过任何一种方式退出时,它将调用 Dispose 关于的参数 using . 从某种意义上说,该块的存在是为了使被指定为 使用 参数,一般来说,这件事不关心块为什么被退出。

    在一些特殊情况下,条款可能会有所帮助;它们的附加效用水平将远远低于 使用 首先(尽管可以说比实现者认为适合提供的一些其他特性要好):

    (1)在对象的构造器或工厂中有一个非常常见的模式,它封装了其他对象。 IDisposable 对象;如果构造函数或工厂通过异常退出,则封装的对象应该 处置 D,但如果它通过 返回 他们不应该。目前,这种行为必须通过 try / catch ,或通过组合 尝试 / finally 有一个旗子,但如果有 使用 只会打电话 处置 当它通过异常退出时,或者 keep using 将使临时雇员无效的声明 使用 保存需要处理的对象的语句(自 使用 不能以标识符开头,这样的功能可以以某种类似于 yield return )

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

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

    推荐文章