我阅读到了关于this scenario的文章,其中使用C# using语句可能会导致问题。如果在using语句末尾调用的Dispose函数也要抛出异常,那么在using块范围内抛出的异常可能会丢失。这强调了在某些情况下,在决定是否添加using语句时应该小心。
我倾向于在使用流和从DbConnection派生的类时使用using语句。如果我需要清理非托管资源,我通常更喜欢使用finally块。
这是IDisposable接口的另一种用法,用于创建性能计时器,该计时器将停止计时器并将时间记录到Dispose函数中的注册表中。http://thebuildingcoder.typepad.com/blog/2010/03/performance-profiling.html
这是IDisposable接口的好用法吗?它没有清理资源或处理任何其他对象。但是,我可以看到它如何通过将正在分析的代码整齐地 Package 在using语句中来清理调用代码。
是否有不应该使用using语句和IDisposable接口的时候?以前在using语句中实现IDisposable或 Package 代码是否给您带来过问题?
谢谢
5条答案
按热度按时间wkyowqbh1#
我要说的是,除非文档告诉您不要使用
using
(如您的示例中所示),否则请始终使用using
。让
Dispose
方法抛出异常会使使用它的目的落空(双关语),无论何时实现它,我总是试图确保无论对象处于什么状态,都不会抛出异常。PS:这里有一个简单的实用方法来补偿WCF的行为。这确保了
Abort
在除了Close
被调用之外的每个执行路径中被调用,并且错误被传播给调用者。如果您在框架中的其他地方发现任何其他有趣的行为案例,您可以提出类似的策略来处理它们。
mqxuamgl2#
一般的经验法则很简单:当类实现IDisposable时,使用
using
。当需要捕获错误时,使用try
/catch
/finally
,以便能够捕获错误。不过,有几点意见。
1.您问是否存在不应使用IDisposable的情况。在大多数情况下,你不需要实现它。当你想及时释放资源时,使用它,而不是等到终结器启动。
1.当IDisposable被实现时,它应该意味着相应的Dispose方法清除它自己的资源,并循环通过任何被引用或拥有的对象,并在它们上调用Dispose。它还应该标记Dispose是否已经被调用,以防止多次清除或被引用对象做同样的事情,从而导致无限循环。然而,所有这些并不能保证对当前对象的所有引用都消失了。这意味着它将保留在内存中,直到所有引用都消失并且终结器启动。
1.在Dispose中抛出异常是不受欢迎的,当它发生时,状态可能不再得到保证。这是一个糟糕的情况。你可以通过使用try/catch/finally来修复它,并在finally块中添加另一个try/catch。但是就像我说的:场面很快就变难看了。
1.使用
using
是一回事,但不要把它与使用try
/finally
混淆。两者是相等的,但using-statement通过添加作用域和空值检查(每次手工操作都很痛苦)使工作变得更容易。using-statement翻译如下(来自C#标准):1.有时候不需要将对象 Package 到using-block中。这种情况很少见。当您发现自己继承了从IDisposable继承的接口时,就会发生这种情况,* 以防 * 子级需要释放。一个常用的示例是IComponent,它与每个Control一起使用(Form、EditBox、UserControl,你能想到的都有)。我很少看到人们用using语句 Package 所有这些控件。另一个著名的例子是
IEnumerator<T>
。当使用它的后代时,也很少看到using块。结论
普遍使用using-statement,并且要谨慎选择替代方法或忽略它。确保你知道使用(不使用)它的含义,并且知道
using
和try/finally的相等性。需要捕获任何东西吗?使用try/catch/finally。svmlkihl3#
我认为更大的问题是在
Dispose
中抛出异常。RAII模式通常明确声明不应该这样做,因为它可以创建像这样的情况。我的意思是,对于没有正确处理的东西,除了简单地结束执行之外,还有什么恢复路径呢?而且,这似乎可以通过两个try-catch语句来避免:
这里唯一可能出现的问题是,如果
DisposeException
是NonDisposeException
的相同类型或超类型,并且您试图重新抛出NonDisposeException
捕获,则DisposeException
块将捕获它,因此您可能需要一些额外的布尔标记来检查这一点。kkbh8khc4#
我所知道的唯一一个例子是WCF客户端。这是由于WCF中的一个设计错误- Dispose应该 * 从不 * 抛出异常。他们错过了这一个。
w8biq8rn5#
一个例子是
IAsyncResult.AsyncWaitHandle
属性。精明的程序员会认识到WaitHandle
类实现了IDisposable
,并自然地试图贪婪地处理它们。除了BCL中的大多数APM实现实际上在属性内部对WaitHandle
进行了惰性初始化。显然,结果是程序员做了比必要的更多的工作。那么问题出在哪里呢?好吧,微软搞砸了
IAsyncResult
接口。如果他们遵循自己的建议,IAsyncResult
将从IDisposable
派生而来,因为其含义是它拥有可处置的资源。精明的程序员将在IAsyncResult
上调用Dispose
,让它决定如何最好地处置其组成部分。这是处理
IDisposable
可能会有问题的典型边缘案例之一。Jeffrey Richter实际上使用这个例子来论证(在我看来是错误的)调用Dispose
不是强制性的。您可以阅读here的争论。