繁体   English   中英

我应该在哪些类中使用C#的using语句?

[英]What classes should I use C#'s using statement with?

我已阅读并且相信我理解C#的using语句的作用(如果我错了,请纠正我):将IDisposable对象初始化为对有限范围( using块)只读。 我知道您可以在using之前using初始化,并且不限制范围,但是建议您在此处使用:

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

我并不总是注意什么类是什么的子类。 我不太确定哪些类从IDisposable继承。 我不仅好奇在using语句中可以使用哪些类,而且我的同事希望在using块中找到哪些类? using块中应该包含哪些类? 另外,不使用using块而不调用Dispose真的有什么问题吗? 它只是关于内存还是稳定性?

严格来说,任何实现IDisposable且范围仅限于该功能的对象都应位于using块内。 存在IDisposable接口,以允许处理非托管资源(数据库连接,文件句柄,窗口句柄等)的类以及时,确定的方式处置这些资源。

通常,在类中使用IDisposable对象的三种方式:

  1. 在单个方法调用的范围内,既创建对象又不再需要该对象。 这是很常见的,并且在using可以(并且应该)使用。
  2. 对象由类创建(或传递给类),并且对象的生存期超出单个方法调用的范围,但不超过类的生存期。 例如,您的类创建一个Stream并且需要在对象的生命周期内使用它。 在这种情况下,您的类应自己实现IDisposable并在调用自己的Dispose方法时Dispose您拥有的对象。 例如System.IO.StreamWriter
  3. 该对象将传递给该类,但是该类并不“拥有”它。 这意味着IDisposable对象的可用生存期超出了单个方法调用的范围,并且可能超出了对象的生存期。 在这种情况下,必须由其他人负责致电Dispose

第一种情况是您会遇到的最常见情况,这就是为什么using块存在的原因。 即使在出现异常的情况下,也要确保确保将对象丢弃。

一些例子:

  • 流类
  • 数据库连接/命令
  • 控制项

没有实现IDisposable的类的详尽列表,因为该列表将很大,并且充满了您可能永远不会遇到的类。 想想类什么; 它会打开某种需要关闭的连接或文件吗? 通常, 它获取某种需要释放的资源吗? 如果是这样,它可能会实现它。 在一个基本水平,如果编译器允许您括在using ,那么它实现IDisposable

至于调用Dispose的后果,请不要考虑。 呼叫Dispose 诚然,防御性标准是,如果您的类直接使用非托管资源,那么您应该定义一个终结器,该终结器将在对象被收集且有人调用失败的情况下调用dispose,但这不是设计选择。 就我所知。

这与内存无关。 它与其他资源有关,例如文件句柄,数据库连接等。

基本上,如果一个类实现了IDisposable ,则表明您应该在完成后将其处置,因为它可能具有不受管的资源,而留下的资源却很昂贵。 (例如,连接池可能用尽了连接,或者文件句柄将保持打开状态,从而防止另一段代码再次打开同一文件)。

您应该始终在实现IDisposable任何类上调用Dispose ,这最容易通过using块完成。

这不仅与记忆有关。 这也不只是资源。 这是关于正确性。

StreamWriter是一个著名的例子。 微软甚至开发了MDA来捕获某些程序员忘记调用Dispose 这不仅仅是内存或资源:在StreamWriter示例中,正在写入的文件可能会被截断。

我不得不一次追踪一个讨厌的错误(实际上是在老板的代码中),在该错误中数据库事务被回滚...原来原因是没有调用Dispose ,所以它试图提交进程退出时,磁盘空间太大(在退出过程中终结器超时)。 修复只是一些using块。

第三个示例:Microsoft的Managed ESENT包装器类具有“三层”处置方案,该方案要求以正确的顺序调用Dispose (最后是“外部”类)。

因此,在三个真实的示例中,如果未正确调用Dispose将导致不正确的行为 其他类可能会表现出类似的行为。

通常,您应该始终调用Dispose

至少,所有使用非托管资源的类

不使用using块而不调用Dispose绝对有很多错误,您很可能会泄漏内存和/或资源。 使用是一种方便,但是您实际上应该在类从IDisposable派生的任何对象中调用Dispose。

至于什么课是一次性的,您可以自己进行智能感知,或者只是从经验中学习。 一些常见的功能包括Image及其子级,实际上是System.Drawing命名空间的大部分,大量文件流,数据库连接等。

至于何时应调用-尽快。 如果您知道它是一次性的,并且知道您已经用完了,请致电Dispose。

我相信许多实现IDisposable的.NET基类都实现了一次性模式,这意味着当垃圾收集器来获取它们时,它们将被正确处理。 但是即使如此,您仍然应该在完成工作后处理事情,因为

  1. 您可能会留下一个参考文献(泄漏),并且它不会被处置,或者
  2. GC可能暂时不会出现。

此外,对于您自己编写的类,垃圾回收并不等同于对非托管资源的正确处理-这是常见的混淆。 一次性模式需要自己实现。

类实现IDisposable主要原因是释放非托管资源。 垃圾回收器将在托管资源超出范围时释放托管资源,它认为合适,但不了解非托管资源。 调用Dispose方法将显式释放资源。

如果您不使用using块或调用Dispose方法,则将出现内存泄漏问题,这又可能导致稳定性问题。

在处理实现IDisposable类时,应始终使用using块。 尽管您可能更喜欢Try.. Catch.. Finally确保在finally块中调用Dispose ,以便您可以处理异常。

IDisposable的目的是使与非托管资源(例如文件,数据库或图形上下文)进行交互的对象能够自行清理。 using语句是以下构造的方便快捷方式

var disposable = new MemoryStream();
try
{
  //do some work with the disposable object
}
finally
{
  if (disposable!=null)
     disposable.Dispose();  
}

当然,问题是要知道哪些对象实现了IDisposable ...不幸的是,除了文档之外,没有自动的方法来知道。 尽管我相信有一个Fxcop设置可以检查在使用之外使用的IDisposables。

您不必担心在using块下使用哪些类。 如果您在using语句下使用过的代码未实现IDisposbale,则它将向您显示红色/蓝色波浪。 这样您就可以知道它缺少idisposable接口。 据我所使用的几乎所有框架类,都已实现Idisposable。 但是在自定义类中,您需要实现

要使用using进行调用的类的准备者是:

  • 数据库连接,命令和数据读取器
  • 读者和作家

您还应该处置更多的类,但是上面的那些类经常被使用,通常在狭窄的使用范围内。

是的-不使用using和不调用dispose存在问题。 经典的Web应用程序不会关闭其与数据库的连接,而是在连接保持打开状态时有效地从数据库服务器吸收资源。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM