如何在使用块内部进行异常处理?

时间:2015-03-27 21:03:22

标签: c#

我只是想知道为什么C#语言不允许你在如下的using语句之后包含一个catch块:

using(var MyObject = new MyObject())
{
    // do work
}
catch(Exception ex)
{
    // log/handle exception
}

这个问题已存在很长时间了,它看起来像一个易于实现的功能,没有任何负面影响,实际上几乎每个程序员都会使用它。是否有正当理由认为C#语言尚未更新以允许此功能,或者是否对该功能的需求不足?

编辑:下面我的评论中有一个(或更多?)提到了WCF使用块的缺点。然而,我后来意识到我错误,因为它适用于这个对话,因为问题是在(自动生成的)finally块中引发异常,而我在这里要求的是访问catch块之间的尝试,最后如果using语句生成一个。

2 个答案:

答案 0 :(得分:6)

回答"的主要问题:如何结合异常处理和使用构造"。答案通常是在我的情况下,我没有。我的大多数异常处理都是在调用堆栈的更高点处理的,集中处理以简化日志记录并知道下一步该做什么(例如,如果我枚举了一组项目,我会在枚举步骤中捕获它以允许我记录该项目失败但继续其余项目。)

但是,如果我将两者结合起来,我会将using包装在try / catch中。您在其他地方提到了使用WCF对象执行此操作的问题,因为它们倾向于使用Dispose()方法抛出。在这种情况下,我会遵循微软的建议而不是完全使用它们,而是手动扩展它们。

我甚至会为finally块添加逻辑,该块具有必要的逻辑,以确保在不会引发异常的情况下不调用Dispose()

要回答有关新语言功能的问题,您的分析不正确。

  

此问题已存在很长时间

什么问题?你指出了一个潜在的句法结构而没有证明目的,并声称它很重要。在添加之前,句法结构面临着很大的特征要求。

WCF周围存在一个小问题,但它听起来像是API问题,而不是语言设计问题。如果您仔细阅读建议,他们会有效地说"关闭连接不是免除异常,因此在此之前手动验证是否安全#34;。

  

它似乎是一个易于实现的功能

研究using构造,您将重新构建它实际上很复杂。 using构造扩展为:(大约)

MyObject MyObject;
try
{
    MyObject = new MyObject()
    // do work
}
finally
{
    if (MyObject != null)
        MyObject.Dispose();
}

通过添加catch,您需要对事物进行重新排序,以便按照正确的语法顺序进行操作(因为catchfinally之前发生)。

  

没有不良影响

你可能已经注意到了,但我忽略了为什么这是错误的。 catch去哪儿了?您是否将其添加为第二个try以确保在执行catch块之前处置对象(与语法中的明显顺序相匹配)或者是否在finally之前添加它?

前者很难自己用try来实现,而后者很难理解,并且可能无论如何都无法正常工作,因为你没有在隐式中捕获异常{ {1}}阻止。

  实际上几乎每个程序员都会使用

大多数人永远不会这样做,而是更喜欢使用显式finally / try来确保try / catch的目的是明确的。还要注意过度使用try / catch,因为这是一个不好习惯。

答案 1 :(得分:3)

您可以通过将try包装在try块中轻松实现此目标,因此:

try
{
     using (var MyObject = new MyObject())
     {
          //do work
     }
}
catch (Exception ex)
{
     //handle exception.
}

所以问题就变成了,为什么设计师将异常处理的概念(即try / catch)块与资源处置的概念联系起来(即using声明)?它会使语言进一步复杂化,因为现在不是一个明确定义的地方catch可以出现,(try之后)它现在还有其他规则(为什么停止使用?为什么不说你可以在任意catch对之后添加{}?)

对于会增加混淆并且不会增加任何实际价值的功能,可能不值得努力。