Search code examples
c#.netidisposable

Should IDisposable be applied cascadingly?


This is a rather basic question, however I'm still struggling with it a little.

IDisposable is implemented, when you want to enable the user of an object to free underlying resources (e.g. sockets etc.) before the object is eventually garbage collected.

When i have a class that holds a DbConnection (implements IDisposable), does my class need to implement IDisposable too and chain the call down to the DbConnection or any other IDisposable objects it owns? Else the DbConnections resources will only be freed when my class is garbage-collected, thereby drops it reference to the connection and GC will finalize the DbConnection.


Solution

  • Yes, you ALWAYS implement IDisposable if you control disposable objects. ALWAYS. Your code won't break if you don't, but it defeats the purpose of having disposable objects if you don't.

    The general rule for GC optimization is:

    • Any class that controls objects not managed by the GC must implement a finalizer (and generally should implement IDisposable as well). This is where the "top level" disposable classes usually come from -- they usually control a HANDLE to a window, socket, mutex, or what have you.
    • Any class that instantiates an IDisposable member should implement IDisposable itself, and properly Dispose() of its constituents.
    • Any function that instantiates an IDisposeable object should properly Dispose() of it when it done being used. Don't let it just drop out of scope.

    These rules may be bent or ignored if you're writing an application for yourself, but when distributing code to others you should be professional and follow the rules.

    The logic here is that when you control memory outside the view of the GC the GC engine can't properly manage your memory usage. On your .NET heap, for example, you may just have a 4-byte pointer, but out in unmanaged land you could have 200 MB of memory being pointed at. The GC engine wouldn't attempt to collect these until you have several dozen, because all it sees is a few bytes; while in the real world it looks a lot like a memory leak.

    Therefore, the rule is, unmanaged memory should get freed immediately when you're done using it (the IDisposable chain does this for you), while managed memory gets freed by the GC engine whenever it gets around to it.