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

时间:2010-07-07 15:28:55

标签: c# using-statement

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

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

我并不总是关注哪些类是什么类的子类。我不太确定哪些类继承自IDisposable。我不只是好奇在using语句中可以使用哪些类,但我的同事希望在using块中找到哪些类?哪些类应该using块中?另外,没有使用using块而不调用Dispose有什么问题吗?是关于记忆还是稳定?

10 个答案:

答案 0 :(得分:15)

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

一般来说,有三种方法可以在一个类中使用IDisposable对象:

  1. 在单个方法调用的范围内创建对象并且不再需要该对象。这很常见,并且可以(并且应该)使用using
  2. 对象由类创建(或传递给类),其生命周期超出了单个方法调用的范围,但不超出类的生命周期。例如,您的类创建了一个Stream,并且需要在对象的生命周期内使用它。在这种情况下,您的类应该实现IDisposable本身并在调用自己的Dispose方法时处置您拥有的对象。这方面的一个例子就是System.IO.StreamWriter
  3. 将对象传递给类,但该类不“拥有”它。这意味着IDisposable对象的可用生命周期超出了单个方法调用的范围,并且可能超出了对象的生命周期。在这种情况下,其他人必须负责致电Dispose
  4. 第一种情况是您将遇到的最常见情况,这就是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基类实现了一次性模式,这意味着当垃圾收集器获取它们时,它们将被正确处理掉。但即便如此,你仍然应该在完成后处理掉事情,因为

  1. 你可以留下一个引用(泄漏),它不会被处理,或
  2. GC可能暂时不会出现。
  3. 此外,对于您自己编写的类,垃圾收集并不等同于对非托管资源的正确处理 - 这是一种常见的混淆。一次性模式需要自己实现。

答案 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应用程序,它不会关闭与数据库的连接,有效地从数据库服务器中吸取资源,因为它保持连接打开。