我已阅读并且我相信我理解C#的using
语句的作用(如果我错了,请纠正我):将IDisposable对象初始化为只读有限范围(using
块)。我知道你可以在using
之前进行初始化,但不限制范围,但建议不要这样做:
http://msdn.microsoft.com/en-us/library/yh598w02.aspx
我并不总是关注哪些类是什么类的子类。我不太确定哪些类继承自IDisposable。我不只是好奇在using
语句中可以使用哪些类,但我的同事希望在using
块中找到哪些类?哪些类应该在using
块中?另外,没有使用using
块而不调用Dispose有什么问题吗?是关于记忆还是稳定?
答案 0 :(得分:15)
严格地说,任何实现IDisposable
并且其范围仅限于该函数的对象应该在using
块内。存在IDisposable
接口,允许处理非托管资源的类(数据库连接,文件句柄,窗口句柄等)以及时,确定的方式处理这些资源。
一般来说,有三种方法可以在一个类中使用IDisposable
对象:
using
。Stream
,并且需要在对象的生命周期内使用它。在这种情况下,您的类应该实现IDisposable
本身并在调用自己的Dispose
方法时处置您拥有的对象。这方面的一个例子就是System.IO.StreamWriter
IDisposable
对象的可用生命周期超出了单个方法调用的范围,并且可能超出了对象的生命周期。在这种情况下,其他人必须负责致电Dispose
。第一种情况是您将遇到的最常见情况,这就是using
块存在的原因。即使在例外的情况下,它也会确保处理对象。
一些例子:
没有详尽的实现IDisposable
的类列表,因为该列表相当大并且填充了您可能永远不会遇到的类。想想所做的;它是否打开某种需要关闭的连接或文件?一般来说,是否会获得某种需要发布的资源?如果是这样,它可能会实现它。在基本级别,如果编译器允许您将其括在using
中,则它会实现IDisposable
。
关于不调用Dispose
的后果,请不要考虑它。 呼叫处理。确实,防御标准是,如果您的类直接使用非托管资源 ,那么您应该定义一个终结器,如果您的对象被收集并且有人未能调用它,则会调用dispose,但是不应该是一个设计选择。永远,据我所知。
答案 1 :(得分:13)
这不是关于记忆的。它涉及其他资源,如文件句柄,数据库连接等。
基本上,如果一个类实现了IDisposable
,那么这是一个信号,你应该在完成后处理它,因为它可能有非托管资源,而这些资源离开时会很昂贵。 (例如,您的连接池可能会用完连接,或者文件句柄将保持打开状态,从而阻止另一段代码再次打开同一文件)。
答案 2 :(得分:2)
您应该始终在实施Dispose
的任何类上调用IDisposable
,这最容易通过using
块完成。
这不仅仅是关于记忆。这也不仅仅与资源有关。这是关于正确性的。
StreamWriter
是一个着名的例子。微软甚至开发了an MDA来捕捉程序员忘记拨打Dispose
的情况。这不仅仅是内存或资源:在StreamWriter
示例中,正在编写的文件可能会被截断。
我不得不一次追踪一个令人讨厌的错误(实际上是在我的老板代码中),数据库事务正在回滚......原因是Dispose
没有被调用,因此它在进程退出时尝试向磁盘提交过多(在进程退出期间终结器超时)。修复只是几个using
块。
第三个例子:Microsoft的Managed ESENT包装器类有一个“三层”处理方案,要求 Dispose
以正确的顺序调用(“外部”类最后)。 / p>
因此,如果未正确调用Dispose
,则有三个真实示例会导致错误行为。其他类可能表现出类似的行为。
作为一般规则,您应始终致电Dispose
。
答案 3 :(得分:1)
至少,所有使用非托管资源的课程
答案 4 :(得分:1)
如果不使用using块并且不调用Dispose,则绝对存在很多错误,您很可能会泄漏内存和/或资源。使用是一种方便,但你真的应该在任何从IDisposable派生类的对象中调用Dispose。
答案 5 :(得分:1)
对于哪些类是一次性的,您可以自己探测intellisense,或者您只是从经验中学习。一些常见的包括Image
及其子节点,实际上大多数System.Drawing
命名空间,大量文件流,数据库连接等。
应尽快召集它。如果您知道它是一次性的,并且您知道已经完成了它,那么请调用Dispose。
我相信许多实现IDisposable
的.NET基类实现了一次性模式,这意味着当垃圾收集器获取它们时,它们将被正确处理掉。但即便如此,你仍然应该在完成后处理掉事情,因为
此外,对于您自己编写的类,垃圾收集并不等同于对非托管资源的正确处理 - 这是一种常见的混淆。一次性模式需要自己实现。
答案 6 :(得分:1)
类实现IDisposable
的主要原因是释放非托管资源。垃圾收集器将在超出范围并且认为合适时释放托管资源,但它不了解非托管资源。调用Dispose方法将显式释放资源。
如果您不使用using
块或调用Dispose
方法,则会出现内存泄漏问题,从而导致稳定性问题。
在处理实现using
的类时,您应始终使用IDisposable
块。虽然您可能希望Try.. Catch.. Finally
确保在Dispose
块中调用finally
,但您可以处理异常。
答案 7 :(得分:1)
IDisposable的目的是使与非托管资源(如文件,数据库或图形上下文)交互的对象能够自行清理。 using语句是以下构造的便捷简写
var disposable = new MemoryStream();
try
{
//do some work with the disposable object
}
finally
{
if (disposable!=null)
disposable.Dispose();
}
问题当然是知道哪些对象实现了IDisposable ......遗憾的是除了文档之外没有自动化的方法。虽然我相信有一个Fxcop设置可以检查在使用之外使用的IDisposable。
答案 8 :(得分:0)
您不必担心在使用块下使用哪些类。如果你使用under using语句没有实现IDisposbale那么它会显示红/蓝波。所以你可以来看看它缺乏idisposable接口。而且就我所使用的几乎所有类的框架都实现了Idisposable。但在自定义类中,您需要实现
答案 9 :(得分:0)
使用using
调用的类的现成计算器是:
您还应该处理更多类,但上面经常使用这些类,通常在狭窄的使用范围内。
是的 - 未使用using
而未调用dispose
存在问题。经典是一个Web应用程序,它不会关闭与数据库的连接,有效地从数据库服务器中吸取资源,因为它保持连接打开。