Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Fundamentals of IDisposable (and some best practices)

0.00/5 (No votes)
31 Aug 2003 1  
For the beginning .NET coder, who does not know OOP well. The article discusses the basics of IDisposable and attempts to show it�s underling simplicity.

Introduction

For some beginning .NET Programmers, the IDisposable interface has elements of confusion. The following article discusses the basics of IDisposable and attempts to show it�s underling simplicity. Also, a straightforward logic is proposed from which the .NET "newbie" can begin.

Background (skip-able)

At work we are beginning the transition to .NET. Things are going pretty well but the road has not been without bumps. No, its not .NET. The problem is how to get VB 6 and PowerBuilder coders over to this powerful and frequently elegant platform. One of the strategies management has taken is to select individuals who we now call "mentors" (I had reservations, but, yes, I was one of the "chosen"). Such persons are, hopefully at least, capable coders who can learn .NET and help others make the jump. Now, the mentors have to take additional .NET training courses. In this one course an odd thing happened. The teacher was covering garbage collection and the related IDisposable interface. When he finished there were many questions. I personally did not like the way the teacher presented the material. All the nitty-gritty details were covered, but that which the new .NET student needs most, "give me the bottom line, when do I use this thing" - were absent. Anyway, what I sensed from some students was confusion. The odd part was, that in the next "mentor" course, the same topic was covered in the same way and the result was, more or less the same.

But let me back up for moment. How do I learn a new language/platform? I buy lots of books and read them - I jump in and just start writing code - basically management knows to leave me alone and I�ll get there. I bring this up because I too paused over this IDisposable issue. I now feel that the real problem I faced was that .Net was new and the best source of info (at least in terms of volume) was Microsoft. Whether you like MS or you don�t or its a love-hate relationship, I don�t think many would disagree that at teaching and documentation, MS has frequently been lacking. I�ve now been coding in .NET for one year. Back then my resolution to such issues was to just move on - and about at three months into .NET it hit me. IDisposable and that Dispose() method - its simple. That there may be others who find this topic somewhat confusing is the reason I wrote this article.

The Role of the Runtime

Below is a conceptual drawing of a particular .NET application and its interaction with the runtime. The reader should be aware that the drawing is simplified (and also, that while the I know something of Windows internals I�m by no means an expert). However, a general knowledge of the runtime�s role, and more specifically, its memory/resource management is all that is required to properly use the IDisposable interface. The drawing shows a .NET application, called "SomeAppOfMine", which is built and then run. In this example the application uses COM InterOp to create and use a COM object.

        ---------------------SomeAppOfMine - (App. Dev. Layer)
        |
        |
        | Build/Run
        |
        |
        |                                .NET Runtime
        v      ________________________________________________
        My IL  |                                              |
        |      | Stack Heap{ ... ObjX ... }<---Manages----GC  |
        |      |               ^  |                           |
        |      |_______________|__|___________________________|
        |                      |  |
        |                      |  |
        |______________________|  |
                                  |
                                  |                   Other Memory
                                  |      ______________
                                  |     |             |
             Request COM Obj.     |     |... ObjY ... |
                                  |     |______^______|
                                  |            |
                                  |            |Creates
         Windows OS layer         |     _______|          
              ____________________|____|_______________________
             |                    v    |                      |
             |               Some Win API                     |
             |                                                |
             |________________________________________________| 

The most important concept in the above drawing is the three-layer architecture. At the top we have the application developer�s space. The design allows one to either delay or be oblivious to the many details of the lower layers. Such an arrangement is appealing because the developer can give full focus to just writing code � at least such is usually the case. There are, however, certain cases which this architecture does not readily solve (such as with the topic at hand). In such a situation a high level view may lead to some confusion, even if the relevant low level details are straightforward. The proper use of IDisposable falls into this category.

In between there is the .NET runtime. The drawing is intentionally laid out, as is, to emphasize the runtime�s "man in the middle" role. By this design an application builds not to machine language but to IL. Some have called this a virtual machine layer. IL code is standardized such that the runtime can completely manage its execution. It is also generalized code that can be, at least in theory, executed on any computer with any operating system (perhaps one of the greatest de-coupling designs in IT history, save for the fact that Java and others I hear, got there first). To understand how to properly use IDisposable, one must make a clear distinction between what is managed and what is not. In terms of IDisposable, the question to be asked is "is the IL code above managed?" The answer, of course is yes � it�s in the middle � its managed.

At the bottom is Windows. To get Windows to do anything one must, some were down the line, call Win APIs. The reason for this approach, too, is rather simple. In C, for example, one can set a pointer to that area of memory where the kernel resides and try to overwrite it. Clearly this would be a bad thing (Visual Studio crashes or, at its worst, "the blue screen of death"). Windows disallows such request by insisting that all use of the computer be funneled through its own API�s. In the above drawing the managed object "ObjX" request, by way of COM Interop, that Windows create a particular COM object. Windows obliges and loads ObjY into memory. The problem that the above design creates is the runtime layer and the windows layer cannot know how, or when, respectively, to do a cleanup proper. The .NET runtime only knows that which is public in the COM object (its exposed interface as is said in "COM speak"). Windows knows everything about what resources the COM object is using as well as what process started it up. But Windows, being so low in the architecture, must be told when to remove the COM object (or wait until the application shuts down). At any rate, just as above, the important question to be asked is "is this COM object managed?" Of course the answer is no.

As an example, and an admittedly extreme one for the sake of illustration, suppose ObjY takes up a lot of memory and/or many system resources (file channels, database connections, TCP sockets, the list of possibilities is quite long). And let the managed IL, being done with ObjX , move on to other chores. ObjX now goes out of scope and is eventually destroyed by the garbage collector. But the IL code, itself, is not done. Or another possibility is that the user moves on to another application but leaves the .NET application up and running. Perhaps the user has assumed that the developer who wrote this .NET application was knowledgeable and this act will not impair (cripple?) the computer�s performance. This would be a completely erroneous assumption. From this example it can be seen that .NET must allow one to dispose of unmanaged resources when they are no longer needed. The situation is so potentially serious that even if the developer has to write a few lines of code and follow some "best practices", such a requirement is clearly superior to no solution at all. As it turns out, this is precisely what the designers of .NET choose to do - and their solution was IDisposable.

Now Some Answers (at last)

IDisposable implements but one method � Dispose(). How then, does the beginning developer decide whether to call Dispose() or perhaps even implement the IDisposable interface in his or her code? With the above concepts in mind, a few simple questions can now be posed. Most scenario's a beginning developer might face where IDisposable issues are relevant will now be divided into just three categories. These will now be discussed. I must also define a new term (of my own creation). The term is "valued code". Valued code could be any of the following:

  1. Code that will or might go into production
  2. Code that will or might be used for some "valued" task
  3. Code that will or might be reused

etc...

"Unvalued code" is everything that is left over. For example, one may be just exploring the use of a particular Framework class for learning purposes. Or one may be attempting to get a Framework class to perform some task, in a particular way. Perhaps to see if it can be done, just because "it would be so cool". In the three cases below, which all involve the IDisposable interface issue, the first two address scenarios were the code is deemed "valued". In the third case the code is not.

Case #1 (valued)

A Framework class is being used (or one that is home grown) which implements IDisposable. When done with the resulting object should Dispose() be called?

Answer � Yes.

Discussion: It is only one extra line of code and the clean up will be less costly. In this case one has little to lose (probably - see the restrictions section below) by making the call and much to gain. And what if its the minimum cost scenario of needing a small object for the applications lifetime and the performance benefit will not be noticeable. Why not let the process shutting down do all the cleanup? I would still recommend that the beginning .NET coder make the call. Best Practices (not just at my company, but for coding in general) dictates this. To some this may seem a little strict and yes, the issue is a bit of a philosophical one. But in the author's opinion a best practice is just that � what one should always do � or if not � have a very good reason for breaking the rule. Its just a good approach to follow best practices even when it has no clear benefit. This way when it does matter one does it automatically.

Case #2 (valued)

A facade layer is being written (chosen for example - it could be any class that's being "used") which eases the use of a Framework class (or a home grown one). Should the facade class implement IDisposable in order to expose this functionality to all users.

Answer - Yes.

Discussion: That�s a yes with only one tiny caveat - that the facade class is not of the "get in - get out - we�re done" type (which is not common in real world ,mid to low level code). Typically the facade must be told when it's users are done. To not implement an IDisposable would be to hide a much needed functionality. Or to say it the OOP way, something that should not be encapsulated, is. What then, one might ask, is a good approach for a proper implementation of IDisposable? A typical technique is to add three methods even though but one is required - this is shown as follows.

 ________________
|                |
|public Dispose()|
|________________|
      |
      |
      | pass in "true"
      |
      |
______V__________________________
|                                |
| protected virtual Dispose(bool)|
| // do a proper clean up        |
|________________________________|
      ^
      |
      |
      | pass in "false"
      |
      |
 _____|_________________
|                       |
| protected ~Finalize() |
|_______________________|

The essential concepts to grasp with the above approach will now be covered. The public Dispose() method is for the users of the class. Not only is it a code declaration but it�s also a very public vocalization (shout?) to all users that they probably should "call me when your done". The finalize method is the exact opposite - only the .NET runtime should call it. The presence of the protected virtual Dispose(bool) method at first may seems subtle, but with a little thought it�s reason for existing, too, becomes clear. There happens to be two reasons. First, this approach obeys a long established best practice of always do a particular thing in one place and one place only. But the addition of OOP adds a second motivation. Assuming the class is not sealed means it is inheritable. If it is inheritable a devout developer will adjust the class�s design such that good inheritance is possible. Could it not occur that when inherited that the user may wish to override the particular dispose approach (morph it)? With Dispose(bool) declared as such, this option remains.

Case #3 (not valued)

The situation is one of the two above but the code is "not valued". Should Dispose() be called (its like case #1) or should IDisposable be implemented (its like case #2).

Answer - No.

Discussion: The situation is clearly one of "who in the heck cares". I can think of but one exception. One wants to write an IDisposable interface for a learning experience.

Some Restrictions

The author wishes to make it clear that the above three cases do not cover all possibilities or all issues. They are proposed as such to give the .NET beginner a point from which to proceed. It is felt that most situations the beginner will face are addressed above. For the sake of general awareness, however, one should remember the following points.

  • The Finalize() method does cause some overhead. Thus, one may encounter situations where leaving this call out should be considered even if best practices says otherwise.
  • If one must inherit from a class which implements IDisposable, there are some additional issues which should be addressed. The beginner could either get a good code sample or ask someone who is more knowledgeable for help.

Just where is this IDisposable?

This can be easy to miss but a few tricks exist which do help. The problem here is that if one looks at the class declaration in MSDN and does not find an IDisposable it should not be concluded that it is not present ("not" three times in one sentence - I�ve been in this business way to long). It could be, and frequently is, inherited previously from a class or interface which is present (for a case and point, check out the ubiquitous "Component" class). A better approach is to just go look for the Dispose() method. Scroll down until the area where the public methods starting with "D" are, or would be if there were any. If there are a large number of classes in the application this approach can be very tedious, to say the least. An even better approach is to open the object browser and examine each one, individually. However, the object browser only displays class�s which one has a reference to. If a class is being examined for potential use, the second alternative is probably the best.

A Happy Ending (conclusion)

Should the beginning developer worry that the IDisposable interface is a odd issue, hopefully, now is now seen as a complete bust. One may return to that warm and cozy high level - back to Visual Studio. Only remember the answer�s to the three cases above and just "go write some code".

Revision History

  • September 02, 2003
    • Removed sections in response to comments by Blake Coverett.
    • Some slight rewording and fixed a few typo's.
  • September 01, 2003
    • A major rewrite from the initial article - several comments received made this need apparent.
    • The original was titled "That Spooky IDisposable?" (now deleted) and was submitted under the SammyLovesC user name (seems corny to me now).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here