Dealing with .NET IDisposable objects

后端 未结 12 762
自闭症患者
自闭症患者 2021-01-30 13:14

I work in C#, and I\'ve been pretty lax about using using blocks to declare objects that implement IDisposable, which you\'re apparently always suppose

相关标签:
12条回答
  • 2021-01-30 13:38

    Always try to use the "using" blocks. For most objects, it doesn't make a big difference however I encountered a recent issue where I implemented an ActiveX control in a class and in didn't clean up gracefully unless the Dispose was called correctly. The bottom line is even if it doesn't seem to make much of a difference, try to do it correctly because some time it will make a difference.

    0 讨论(0)
  • 2021-01-30 13:45

    Unfortunately, neither FxCop or StyleCop seem to warn on this. As other commenters have mentioned, it is usually quite important to make sure to call dispose. If I'm not sure, I always check the Object Browser (Ctrl+Alt+J) to look at the inheritance tree.

    0 讨论(0)
  • 2021-01-30 13:47

    FxCop might help (although it didn't spot a test I just fired at it); but yes: you are meant to check. IDisposable is simply such an important part of the system that you need to get into this habit. Using intellisense to look for .D is a good start (though not perfect).

    However, it doesn't take long to familiarize yourself with types that need disposal; generally anything involving anything external (connection, file, database), for example.

    ReSharper does the job too, offering a "put into using construct" option. It doesn't offer it as an error, though...

    Of course, if you are unsure - try using it: the compiler will laugh mockingly at you if you are being paranoid:

    using (int i = 5) {}
    
    Error   1   'int': type used in a using statement must be implicitly convertible to 'System.IDisposable'    
    
    0 讨论(0)
  • 2021-01-30 13:47

    @Atario, not only the accepted answer is wrong, your own edit is as well. Imagine the following situation (that actually occurred in one CTP of Visual Studio 2005):

    For drawing graphics, you create pens without disposing them. Pens don't require a lot of memory but they use a GDI+ handle internally. If you don't dispose the pen, the GDI+ handle will not be released. If your application isn't memory intensive, quite some time can pass without the GC being called. However, the number of available GDI+ handles is restricted and soon enough, when you try to create a new pen, the operation will fail.

    In fact, in Visual Studio 2005 CTP, if you used the application long enough, all fonts would suddenly switch to “System”.

    This is precisely why it's not enough to rely on the GC for disposing. The memory usage doesn't necessarily corelate with the number of unmanaged resources that you acquire (and don't release). Therefore, these resoures may be exhausted long before the GC is called.

    Additionally, there's of course the whole aspects of side-effects that these resources may have (such as access locks) that prevent other applications from working properly.

    0 讨论(0)
  • 2021-01-30 13:48

    If an object implements the IDisposable interface, then it is for a reason and you are meant to call it and it shouldn't be viewed as optional. The easiest way to do that is to use a using block.

    Dispose() is not intended to only be called by an object's finalizer and, in fact, many objects will implement Dispose() but no finalizer (which is perfectly valid).

    The whole idea behind the dispose pattern is that you are providing a somewhat deterministic way to release the unmanaged resources maintained by the object (or any object in it's inheritance chain). By not calling Dispose() properly you absolutely can run in to a memory leak (or any number of other issues).

    The Dispose() method is not in any way related to a destructor. The closest you get to a destructor in .NET is a finalizer. The using statement doesn't do any deallocation...in fact calling Dispose() doesn't do any deallocation on the managed heap; it only releases unmanaged resources that had been allocated. The managed resources aren't truely deallocated until the GC runs and collects the memory space allocated to that object graph.

    The best ways to determine if a class implements IDisposable are:

    • IntelliSense (if it has a Dispose() or a Close() method)
    • MSDN
    • Reflector
    • Compiler (if it doesn't implement IDisposable you get a compiler error)
    • Common sense (if it feels like you should close/release the object after you're done, then you probably should)
    • Semantics (if there is an Open(), there is probably a corresponding Close() that should be called)
    • The compiler. Try placing it in a using statement. If it doesn't implement IDisposable, the compiler will generate an error.

    Think of the dispose pattern as being all about scope lifetime management. You want to acquire the resource as last as possible, use as quickly as possibly, and release as soon as possible. The using statement helps to do this by ensuring that a call to Dispose() will be made even if there are exceptions.

    0 讨论(0)
  • 2021-01-30 13:48

    In short, it's not the end of the world if I miss a using. I just wish something would generate at least a warning for it.

    The problem here is that you can't always deal with an IDisposable by just wrapping it up in a using block. Sometimes you need the object to hang around for a bit longer. In which case you will have to call its Dispose method explicitly yourself.

    A good example of this is where a class uses a private EventWaitHandle (or an AutoResetEvent) to communicate between two threads and you want to Dispose of the WaitHandle once the thread is finished.

    So it isn't as simple as some tool just checking that you only create IDisposable objects within a using block.

    0 讨论(0)
提交回复
热议问题