开发者

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). I know you can initialize before the using and that doesn't limit the scope, but that is advised against here:

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. 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? What classes should be in a using block? Also, is there really anything wrong with not using a using block and not calling 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. 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.

There are, in general, three ways in which an IDisposable object is used within a class:

  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.
  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. 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. An example of this would be something like 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. In this case, someone else must be responsible for calling Dispose.

The first case is the most common that you'll encounter, which is why the using block exists. 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. 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.

As to the consequences of not calling Dispose, don't consider it. Call 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. 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. (e.g. 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.

This is not just about memory. This is also not just about resources. This is about correctness.

StreamWriter is a famous example. Microsoft has even developed an MDA to catch some cases where programmers forgot to call Dispose. This is more than just memory or resources: in the StreamWriter example, a file being written may be truncated.

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). The fix was just a few using blocks.

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).

So, there are three real-world examples where incorrect behavior will result if Dispose is not called properly. Other classes may exibit similar behavior.

As a general rule, you should always call Dispose.


At least, all class that used non managed resources


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 is a convenience, but you really should call Dispose in any object which class derives from IDisposable.


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.

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.

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. 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.

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. 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.

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.

You should use a using block at all times when dealing with classes that implement IDisposable. Although you may prefer a Try.. Catch.. Finally ensuring that you call Dispose in the finally block so you can deal with exceptions.


The purpose of IDisposable is to enable objects that interact with unmanaged resources (like files, databases, or graphics contexts) to clean up after themselves. A using statement is a convenient shorthand for the following construct

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. Although I believe there is an Fxcop setting that will check for IDisposables used outside of a using.


you need not to worry about using what classes under using blocks. If the you have used under using statement doesnot implements IDisposbale then it will show you red/blue wave. So that you can come to knwo that its lacking idisposable interface. And as far as i have used almost all classes of framework has Idisposable implemented. but in custom class , you need to implement


A ready-reckoner of classes to call with using is:

  • 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. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜