GOTCHA 41 Using the Dispose Design Pattern doesn t guarantee cleanup


GOTCHA #41 Using the Dispose Design Pattern doesn't guarantee cleanup

While the IDisposable interface and the Dispose Design Pattern are very important to follow, these are recommendations on how you write a class, not how you use an instance of the class. If you create an object, the CLR may eventually call its Finalize(). On the other hand, Dispose() is never called automatically. Users of your object have the responsibility of calling it. What if they forget to?

The problem does not end there. Even if you have a call to Dispose(), what if an exception is thrown before the program reaches that statement? What can you do to ensure that Dispose() is called and thereby increase the probability of proper cleanup?

To deal with these issues, C# offers the using keyword (though there is no way to force the user to use it). Consider Example 5-10.

Example 5-10. Code that utilizes the using keyword

C# (Using)

 //Test.cs using System; namespace DisposePattern {     class Test     {         [STAThread]         static void Main(string[] args)         {             using(Derived object1 = new Derived(1))             {                 Derived object2 = new Derived(2);             }         }     } } 

In this example, you use the using keyword when creating object1 of the Derived class. You do not call its Dispose() method. (The class Derived is the same as the one used in Example 5-7.) The using keyword provides a significant benefit. It not only makes the call to Dispose(), it does so in a finally block, as the generated MSIL in Figure 5-8 shows. This ensures that the object is disposed of properly even when an exception is thrown.

Figure 5-8. MSIL generated for Main() in Example 5-10


You can declare more than one reference in the using declaration:

 using(Derived obj1 = new Derived(1), obj2 = new Derived(2)) 

The Dispose() method, in this case, will be called on each referenced object at the appropriate time.

Unfortunately, using is only available in C#. In VB.NET, to make sure Dispose() is invoked, call it in a Finally block. A VB.NET example of calling Dispose() in the Finally block is shown below:

             Try                 theWrapper = New Wrapper                 result = theWrapper.doSomething()             Finally                 theWrapper.Dispose()             End Try 

How does this differ in .NET 2.0 Beta 1? A Using...End Using block is being introduced in the next version of VB.NET.

IN A NUTSHELL

The using keyword in C# improves your chances of cleaning up your resources properly. In VB.NET, you have to take responsibility for invoking Dispose() by calling it within a Finally block. Take advantage of the Using...End Using block when you move to .NET 2.0.

SEE ALSO

Gotcha #35, "Writing Finalize( ) is rarely a good idea," Gotcha #36, "Releasing managed resources in Finalize( ) can wreak havoc," Gotcha #37, "Rules to invoke base.Finalize( ) are not consistent," Gotcha #38, "Depending on Finalize() can tie up critical resources," Gotcha #39, "Using Finalize() on disposed objects is costly," and Gotcha #40, "Implementing IDisposable isn't enough."



    .NET Gotachas
    .NET Gotachas
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 126

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net