我已经读过这样的使用:
using (myObject)
{
myObject.DoStuff();
}
可以这样想:
try
{
myObject.DoStuff();
}
finally
{
myobject.Dispose()
}
因此,如果myObejct.DoStuff抛出ExceptionA
,然后myObject.Dispose()也抛出异常(ExceptionB),则ExceptionA
将丢失。 (有关更好的说明,请参阅MSDN examples here。)
这是否意味着如果使用块代码中的代码可能抛出异常(大多数代码是正确的?)那么using
语句是不好的做法?
答案 0 :(得分:18)
这是否意味着如果使用块代码中的代码可能抛出异常(大多数代码是正确的?)那么使用using语句是不好的做法?
没有
然后myObject.Dispose()也抛出异常
这确实是你问题的症结所在。
这是“坏习惯”。 IDisposable.Dispose
实现应该真正设计,以便它们不会引发异常,除非在真正无法恢复的情况下。
由于IDisposable
确实是为了释放有问题的资源,因此主要问题应该是确保在大多数情况下不会抛出此实现。使用清理方法抛出会引起很多悲伤 - 这也是using statement shouldn't be used with WCF clients等等的原因。
话虽如此,我认为使用声明本身并不是一种坏习惯。事实上,它往往是一种非常好的做法,因为它避免了一个非常常见的陷阱(在例外情况下缺少一次性资源)。
答案 1 :(得分:6)
using
语句可确保正确处理实现IDisposable
的类型(即syntactic sugar正确实现Dispose pattern)。
他们非常良好做法。
使用 Dispose 函数抛出是不好的做法。
答案 2 :(得分:6)
这是WCF中的常见问题,Dispose()经常抛出异常。有一种方法可以包装一次性使您可以继续获得using()语句的好处,而不会有丢失异常的风险。它基本上吞噬了Dispose期间抛出的任何异常,因此原始异常总是被抛出到更高的上下文中。
http://marcgravell.blogspot.com/2008/11/dontdontuse-using.html
答案 3 :(得分:2)
.net中异常处理的一个基本限制是,由于它是通过C ++异常处理模型构建的,因此所有与当前异常上下文相关的信息都必须封装在一个异常对象中;实际上,在C#中,所有与是否应该捕获异常相关的信息都必须封装在一个异常对象的类型中。此外,在C#中,发现异常的唯一方法就是同意捕获它,并且没有办法以声明的方式表明一个人希望对异常采取行动,但无意对其进行充分处理。被视为“已解决”。所引用的“使用”困难源于这些限制。
在现实世界中,Dispose()
期间发生的事情可能会破坏任何不期望它们的代码流。这种情况通常应该是例外。不幸的是,如果Dispose
正在运行,因为发生了一些其他异常,并且在其中发生异常,那么在C#中只有三个实际操作过程:
在vb.net中,第四种可能性具有更好的语义,但需要看起来很奇怪的代码:Exception
并使用异常过滤器来锁定,而不会捕获变量发生的任何异常,如同上面的#3,在“finally”块中对该变量进行操作。
“using”语句提供上面列出的第一个语义。在某些情况下,其他方法可能会更好。我希望vb和C#提供一个“finally”语句的版本,该语句接受Exception
类型的参数。它可以允许上面的#4语义(在语义上是最好的)没有丑陋的代码。