Free mag vol1 | Page 554

CHAPTER 13  UNDERSTANDING OBJECT LIFETIME managed and unmanaged resources. However, when the garbage collector initiates the cleanup, we specify false when calling CleanUp() to ensure that internal disposable objects are not disposed (as we can’t assume they are still in memory!). Last but not least, our bool member variable (disposed) is set to true before exiting CleanUp() to ensure that Dispose() can be called numerous times without error.  Note After an object has been “disposed,” it’s still possible for the client to invoke members on it, as it is still in memory. Therefore, a robust resource wrapper class would also need to update each member of the class with additional coding logic that says, in effect, “If I am disposed, do nothing and return from the member.” To test our final iteration of MyResourceWrapper, add a call to Console.Beep() within the scope of your finalizer, like so: ~MyResourceWrapper() { Console.Beep(); // Call our helper method. // Specifying "false" signifies that // the GC triggered the cleanup. CleanUp(false); } Next, update Main() as follows: static void Main(string[] args) { Console.WriteLine("***** Dispose() / Destructor Combo Platter *****"); // Call Dispose() manually. This will not call the finalizer. MyResourceWrapper rw = new MyResourceWrapper(); rw.Dispose(); } // Don't call Dispose(). This will trigger the finalizer // and cause a beep. MyResourceWrapper rw2 = new MyResourceWrapper(); Notice that we are explicitly calling Dispose() on the rw object, so the destructor call is suppressed. However, we have “forgotten” to call Dispose() on the rw2 object and, therefore, when the application terminates, we hear a single beep. If you were to comment out the call to Dispose() on the rw object, you would hear two beeps.  Source Code The FinalizableDisposableClass project is included under the Chapter 13 subdirectory. 495