简体   繁体   English

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

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

I've read and I believe I understand what C#'s using statement does (please correct me if I'm wrong): Initializes an IDisposable object as read only to a limited scope (the using block). 我已阅读并且相信我理解C#的using语句的作用(如果我错了,请纠正我):将IDisposable对象初始化为对有限范围( using块)只读。 I know you can initialize before the using and that doesn't limit the scope, but that is advised against here: 我知道您可以在using之前using初始化,并且不限制范围,但是建议您在此处使用:

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

I'm not always paying attention to what classes are subclasses of what. 我并不总是注意什么类是什么的子类。 I'm not too sure what classes inherit from IDisposable. 我不太确定哪些类从IDisposable继承。 I'm not just curious what classes can be used in a using statement, but what classes would my coworkers expect to find in a using block? 我不仅好奇在using语句中可以使用哪些类,而且我的同事希望在using块中找到哪些类? What classes should be in a using block? using块中应该包含哪些类? Also, is there really anything wrong with not using a using block and not calling Dispose? 另外,不使用using块而不调用Dispose真的有什么问题吗? Is it just about memory or also stability? 它只是关于内存还是稳定性?

Strictly speaking, any object that implements IDisposable and whose scope is limited to that function should be within a using block. 严格来说,任何实现IDisposable且范围仅限于该功能的对象都应位于using块内。 The IDisposable interface exists to allow classes that deal with unmanaged resources (database connections, file handles, window handles, etc.) to dispose of these resources in a timely, deterministic fashion. 存在IDisposable接口,以允许处理非托管资源(数据库连接,文件句柄,窗口句柄等)的类以及时,确定的方式处置这些资源。

There are, in general, three ways in which an IDisposable object is used within a class: 通常,在类中使用IDisposable对象的三种方式:

  1. The object is both created and no longer needed within the scope of a single method call. 在单个方法调用的范围内,既创建对象又不再需要该对象。 This is quite common, and is when using can (and should) be used. 这是很常见的,并且在using可以(并且应该)使用。
  2. The object is created by the class (or is passed to the class), and its lifetime extends beyond the scope of a single method call but not beyond the life of the class. 对象由类创建(或传递给类),并且对象的生存期超出单个方法调用的范围,但不超过类的生存期。 For example, your class creates a Stream and needs to use it over the lifetime of the object. 例如,您的类创建一个Stream并且需要在对象的生命周期内使用它。 In this case, your class should implement IDisposable itself and dispose of the object(s) that you own when your own Dispose method is called. 在这种情况下,您的类应自己实现IDisposable并在调用自己的Dispose方法时Dispose您拥有的对象。 An example of this would be something like System.IO.StreamWriter 例如System.IO.StreamWriter
  3. The object is passed to the class, but the class doesn't "own" it. 该对象将传递给该类,但是该类并不“拥有”它。 This means that the IDisposable object's usable lifetime is beyond the scope of a single method call, and may be beyond the lifetime of your object. 这意味着IDisposable对象的可用生存期超出了单个方法调用的范围,并且可能超出了对象的生存期。 In this case, someone else must be responsible for calling Dispose . 在这种情况下,必须由其他人负责致电Dispose

The first case is the most common that you'll encounter, which is why the using block exists. 第一种情况是您会遇到的最常见情况,这就是为什么using块存在的原因。 It takes care of ensuring that the object will be disposed of, even in the case of an exception. 即使在出现异常的情况下,也要确保确保将对象丢弃。

Some examples: 一些例子:

  • Stream classes 流类
  • Database connections/commands 数据库连接/命令
  • Controls 控制项

There's no exhaustive list of classes that implement IDisposable , as that list would be fairly large and filled with classes that you'll likely never encounter. 没有实现IDisposable的类的详尽列表,因为该列表将很大,并且充满了您可能永远不会遇到的类。 Think about what the class does ; 想想类什么; does it open some sort of connection or file that needs to be closed? 它会打开某种需要关闭的连接或文件吗? In general, does it acquire some kind of resource that needs to be released ? 通常, 它获取某种需要释放的资源吗? If so, it probably implements it. 如果是这样,它可能会实现它。 At a basic level, if the compiler allows you to enclose it in using , then it implements IDisposable . 在一个基本水平,如果编译器允许您括在using ,那么它实现IDisposable

As to the consequences of not calling Dispose , don't consider it. 至于调用Dispose的后果,请不要考虑。 Call Dispose . 呼叫Dispose True, the defensive standard is that if your class uses unmanaged resources directly , then you should define a finalizer that will call dispose in the event that your object is collected and someone has failed to call it, but that should not be a design choice. 诚然,防御性标准是,如果您的类直接使用非托管资源,那么您应该定义一个终结器,该终结器将在对象被收集且有人调用失败的情况下调用dispose,但这不是设计选择。 Ever, as far as I'm aware. 就我所知。

It's not about memory. 这与内存无关。 It's about other resources such as file handles, database connections etc. 它与其他资源有关,例如文件句柄,数据库连接等。

Basically if a class implements IDisposable , that's a signal that you should dispose of it when you're done, because it may have unmanaged resources which would be expensive to leave around. 基本上,如果一个类实现了IDisposable ,则表明您应该在完成后将其处置,因为它可能具有不受管的资源,而留下的资源却很昂贵。 (eg your connection pool may run out of connections, or a file handle will stay open, preventing another piece of code from opening the same file again). (例如,连接池可能用尽了连接,或者文件句柄将保持打开状态,从而防止另一段代码再次打开同一文件)。

You should always call Dispose on any class that implements IDisposable , and this is most easily done via a using block. 您应该始终在实现IDisposable任何类上调用Dispose ,这最容易通过using块完成。

This is not just about memory. 这不仅与记忆有关。 This is also not just about resources. 这也不只是资源。 This is about correctness. 这是关于正确性。

StreamWriter is a famous example. StreamWriter是一个著名的例子。 Microsoft has even developed an MDA to catch some cases where programmers forgot to call Dispose . 微软甚至开发了MDA来捕获某些程序员忘记调用Dispose This is more than just memory or resources: in the StreamWriter example, a file being written may be truncated. 这不仅仅是内存或资源:在StreamWriter示例中,正在写入的文件可能会被截断。

I had to track down a nasty bug one time (in my boss' code, actually), where a database transaction was being rolled back... turns out the cause was that Dispose wasn't being called, so it was trying to commit too much to disk when the process exited (there's a timeout for finalizers during process exit). 我不得不一次追踪一个讨厌的错误(实际上是在老板的代码中),在该错误中数据库事务被回滚...原来原因是没有调用Dispose ,所以它试图提交进程退出时,磁盘空间太大(在退出过程中终结器超时)。 The fix was just a few using blocks. 修复只是一些using块。

A third example: Microsoft's Managed ESENT wrapper classes have a "three tier" disposal scheme that requires Dispose to be called in the correct order ("outer" classes last). 第三个示例:Microsoft的Managed ESENT包装器类具有“三层”处置方案,该方案要求以正确的顺序调用Dispose (最后是“外部”类)。

So, there are three real-world examples where incorrect behavior will result if Dispose is not called properly. 因此,在三个真实的示例中,如果未正确调用Dispose将导致不正确的行为 Other classes may exibit similar behavior. 其他类可能会表现出类似的行为。

As a general rule, you should always call Dispose . 通常,您应该始终调用Dispose

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

There is absolutely a lot wrong with not using a using block and not calling Dispose, you most likely will leak memory and / or resources. 不使用using块而不调用Dispose绝对有很多错误,您很可能会泄漏内存和/或资源。 Using is a convenience, but you really should call Dispose in any object which class derives from IDisposable. 使用是一种方便,但是您实际上应该在类从IDisposable派生的任何对象中调用Dispose。

As far as what classes are disposable, you can probe intellisense yourself, or you'll just learn from experience. 至于什么课是一次性的,您可以自己进行智能感知,或者只是从经验中学习。 Some common ones include Image and its children, in fact most of System.Drawing namespace, plenty of file streams, database connections, etc. 一些常见的功能包括Image及其子级,实际上是System.Drawing命名空间的大部分,大量文件流,数据库连接等。

As far as when it should be called - as soon as possible. 至于何时应调用-尽快。 If you know it's disposable, and you know you're done with it, then call Dispose. 如果您知道它是一次性的,并且知道您已经用完了,请致电Dispose。

I believe many of the .NET base classes that implement IDisposable implement the disposable pattern, which means that they will be disposed of, properly, when the garbage collector comes to get them. 我相信许多实现IDisposable的.NET基类都实现了一次性模式,这意味着当垃圾收集器来获取它们时,它们将被正确处理。 But even so, you should still dispose of things when you're done, because 但是即使如此,您仍然应该在完成工作后处理事情,因为

  1. You may leave a reference hanging around (a leak) and it won't be disposed, or 您可能会留下一个参考文献(泄漏),并且它不会被处置,或者
  2. The GC may not come around for a while. GC可能暂时不会出现。

Additionally, for classes you write yourself, garbage collection does NOT equate to proper disposal for unmanaged resources - a common confusion. 此外,对于您自己编写的类,垃圾回收并不等同于对非托管资源的正确处理-这是常见的混淆。 The disposable pattern needs to be implemented yourself. 一次性模式需要自己实现。

The main reason a class would implement IDisposable is to release non managed resources. 类实现IDisposable主要原因是释放非托管资源。 The garbage collector will release managed resources as they go out of scope and it sees fit, but it has no knowledge of non managed resources. 垃圾回收器将在托管资源超出范围时释放托管资源,它认为合适,但不了解非托管资源。 Calling the Dispose method will explicitly release the resources. 调用Dispose方法将显式释放资源。

If you do not use a using block or call the Dispose method then you will have a problem with memory leakage, which in turn could cause stability issues. 如果您不使用using块或调用Dispose方法,则将出现内存泄漏问题,这又可能导致稳定性问题。

You should use a using block at all times when dealing with classes that implement IDisposable . 在处理实现IDisposable类时,应始终使用using块。 Although you may prefer a Try.. Catch.. Finally ensuring that you call Dispose in the finally block so you can deal with exceptions. 尽管您可能更喜欢Try.. Catch.. Finally确保在finally块中调用Dispose ,以便您可以处理异常。

The purpose of IDisposable is to enable objects that interact with unmanaged resources (like files, databases, or graphics contexts) to clean up after themselves. IDisposable的目的是使与非托管资源(例如文件,数据库或图形上下文)进行交互的对象能够自行清理。 A using statement is a convenient shorthand for the following construct using语句是以下构造的方便快捷方式

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

The problem of course is knowing which objects implement IDisposable...unfortunately there is no automated way to know besides the docs. 当然,问题是要知道哪些对象实现了IDisposable ...不幸的是,除了文档之外,没有自动的方法来知道。 Although I believe there is an Fxcop setting that will check for IDisposables used outside of a using. 尽管我相信有一个Fxcop设置可以检查在使用之外使用的IDisposables。

you need not to worry about using what classes under using blocks. 您不必担心在using块下使用哪些类。 If the you have used under using statement doesnot implements IDisposbale then it will show you red/blue wave. 如果您在using语句下使用过的代码未实现IDisposbale,则它将向您显示红色/蓝色波浪。 So that you can come to knwo that its lacking idisposable interface. 这样您就可以知道它缺少idisposable接口。 And as far as i have used almost all classes of framework has Idisposable implemented. 据我所使用的几乎所有框架类,都已实现Idisposable。 but in custom class , you need to implement 但是在自定义类中,您需要实现

A ready-reckoner of classes to call with using is: 要使用using进行调用的类的准备者是:

  • Streams
  • Database connections, commands and data readers 数据库连接,命令和数据读取器
  • Readers and Writers 读者和作家

There are many many more classes which you should also Dispose, but those above are frequently used, often in narrow usage scope. 您还应该处置更多的类,但是上面的那些类经常被使用,通常在狭窄的使用范围内。

Yes - there are issues with not using using and not calling dispose . 是的-不使用using和不调用dispose存在问题。 A classic is a web app which does not close its connections to a database, effectively sucking resources from the database server as it holds connections open. 经典的Web应用程序不会关闭其与数据库的连接,而是在连接保持打开状态时有效地从数据库服务器吸收资源。

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

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