Francesco's blog

Searched for : Dispose/Finalize

As I anticipated yesterday, here is the TOC of my newest Programming Microsoft Visual Basic 2005, to be available in stores in early January.

Part I : The Basics
 1. Introducing the .NET Framework
(12 pages): a quick overview of basic concepts in .NET programming.
 2. Basic Language Concepts (70 pages): modules, classes, variables, arrays, operators, etc. plus what you need to know about inheritance and attributes so that you can read next chapters, before chapter 8 and 19.
 3. Control Flow and Error Handling (40 pages): If, Select, For, For Each and other basic statements; error handling, with many not-so-obvious techniques to improve code efficiency and programming style.

 4. Using Visual Studio 2005 (56 pages): the many new features of VS2005 IDE, plus many old features that not all developers know; how to write a code snippet for VS2005; templates, refactoring, and a brief but intense tutorial on VS macros.

 5. Debugging and Testing (56 pages): breakpoints and tracepoints, data tips, how to write a cusom visualizers, trace commands and trace listeners (including custom listeners), benchmarks and profiling, unit testing, and code coverage.

Part II : Object-Oriented Programming
 6.
Class Fundamentals (42 pages): the "usual" story about classes, methods, properties, etc. plus the new partial classes and operator overloading, all peppered with the description of relatively unknown programming techniques.
 7. Delegates and Events (26 pages): a small chapters with many details and secrets on how to use these VB features in real-world apps. It includes the new custom events.
 8. Inheritance (34 pages): inheritance at its best, including visual (form) inheritance and many real examples.

 9. Object Lifetime (28 pages): everything you might need to know about garbage collection, the Dispose/Finalize pattern, weak references, GC generations, object resurrection, and other advanced techniques that can take your app to the next level
10. Interfaces (28 pages): how to define a custom interface and, above all, how to leverage those that .NET provides you with, such as IComparer and IEnumerable.
11. Generics (40 pages): half of what you want to know about this new great .NET 2.0 feature (the second half is in chapter 13), including constraints, nullable types, and many examples of programming techniques that are based on generics.

Part III : Working with the .NET Framework
12. .
NET Basic Types (50 pages): working with strings, numbers, and dates at their best, including many little/big new features of .NET 2.0
13. Arrays and Collections (53 pages): arrays, jagged arrays, "traditional" and generics collections, plus many tricks for writing less code that runs faster.
14. Regular Expressions (40 pages): a reference of regex syntax, plus many practical examples on data validation, data parsing, and even code parsing. If you aren't familiar with regexs you are missing a great occasion for writing better code in less time.
15. Files and Streams (42 pages): an overview of all the types in System.IO and the many new features in .NET 2.0, including ACL support, compressed streams, and the TextFieldParser type.
16. The My Namespace (48 pages): how to use the My namespace and how to extend it as you need.
17. Assemblies and Resources (44 pages): despite of their importance, resources (either simple or localized) are used rarely and unproperly by most developers; this chapter includes a complete description of the many important features added to NGEN.

Parti IV : Advanced Topics
18. Reflection
(58 pages): there is a lot to say about reflection; among the many examples I wrote an app that generates code on the fly, a scheduler for undoable actions, and a universal comparer class.
19. Custom Attributes (46 pages): this chapter includes a few complete and nontrivial examples of how a custom attribute can make your coding simpler, for example by means of Windows Forms plugins and a framework for n-tier apps.

20. Threads (54 pages): the Thread object, asynchronous delegates, thread pool, the SyncLock statement, all the synchronization types, including the new Semaphore. Plus a section on threading in Windows Forms aoos.
21. Object Serialization (32 pages): binary and SOAP serialization, version-tolerant serialization in .NET 2.0, the new attributes for serializatoin, custom serialization, serialization surrogates, the IObjectReference interface, and more.
22 PInvoke and COM Interop (40 pages): How to interact with unmanaged code: calling "classic" DLL and Windows API methods; using COM components (including the new registration-free components); writing .NET components that can be used from COM apps.

As I already explained, this book isn't a mere VB 2005 reference. Better, in addition to being a complete reference book, it is a digest of the many programming techniques that you can implement by leveraging the features of the language and the .NET Framework 2.0, including generics, threads, reflection, custom attributes, serialization, delegate, regular expressions, and more. All descriptions aim to writing faster and more robust code. I looked hard for a similar book on the market before writing this one. I believe I finally wrote a book that does VB justice.

It has been a real tour de force, which kept me busy from May, summer included. Today I have completed the very last edit to PDFs, then everything goes to the printer!

12/16/2005 2:32:12 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

Every now and then I get an email from a reader or a customer, who asks for clarifications on object finalization and disposing. As far as I know, the best article on this topic is this essay by Joe Duffy. It's over 25-page long, covers both .NET 1.1 and 2.0, and includes comments from gurus such as Jeffrey Richter e Chris Brumme. This is easily the definitive article on this topic and I urge you to read it if you haven't already.

The Dispose-Finalize pattern is objectively a complex matter. However, in most cases it can be simplified significantly if you use the following approach: (1) the class with the Dispose/Finalize method should wrap only one single unmanaged resource, and (2) this finalizable class should be private and nested inside another disposable (but not finalizable) type. The outer class is the only class that can use the finalizable class.

This simple trick enables the GC to immediately release all the memory used by the wrapper (disposable) class even in the worst case - that is, if the client code omits to invoke the Dispose method - and simplifies the structure of the type that uses the unmanaged resource. A listing is worth one thousand words, thus here is the C# version of what I mean:

// the class that clients use to work with the unmanaged resource
class WinResource : IDisposable
{
  // private field that creates a wrapper for the unmanaged resource
  private UnmanagedResourceWrapper wrapper = null;
  // this is true if the object has been disposed of
  bool disposed = false;

  public WinResource(string someData)
  {
    // allocate the unmanaged resource here
    wrapper = new UnmanagedResourceWrapper(someData);
  }

  // a public method that clients call to work with the unmanaged resource
  public void DoSomething()
  {
    // throw if the object has been already disposed of
    if ( disposed )
      throw new ObjectDisposedException("");

    // this code can pass the wrapper.Handle value to API calls.
    // ...
  }

  public void Dispose()
  {
    // avoid issues when multiple threads call Dispose at the same time.
    lock ( this )
    {
      // do nothing if already disposed of
      if ( disposed )
        return;
      // dispose of all the disposable objects used by this instance
      // including the one that wraps the unmanaged resource
      // ...
      wrapper.Dispose();
      // remember this object has been disposed of
      disposed = true;
    }
  }
 
  // the nested private class that allocates and release the unmanaged resource
  private sealed class UnmanagedResourceWrapper : IDisposable
  {
    // an invalid handle value, that the wrapper class can use to check
    // whether the handle is valid
    public static readonly IntPtr InvalidHandle = new IntPtr(-1);

    // a public field, but accessible only from inside the WinResource class 
    public IntPtr Handle = InvalidHandle;

    // the constructor takes some data and allocates the unmanaged resource (eg a file)
    public UnmanagedResourceWrapper(string someData)
    {
      // this is just a demo...
      this.Handle = new IntPtr(12345);
    }

    // the Dispose method can be invoked only by WinResource class
    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    // the finalizer
    ~UnmanagedResourceWrapper()
    {
      Dispose(false);
    }

    // This is where the unmanaged resource is actually disposed of.
    // Notice that it takes an argument only for compliance with .NET coding standards
    // but the disposing argument is never used, because in all cases this class
    // can access and release only the single unmanaged resource it wraps.
    private void Dispose(bool disposing)
    {
      // exit now if this object didn't completed its constructor correctly
      if ( this.Handle == InvalidHandle )
        return;
  
      // release the unmanaged resource 
      // eg. CloseHandle(Handle);
      
      // finally, invalidate the handle
      this.Handle = InvalidHandle;
    }
  }
}

Notice that, if the unmanaged resource must interact with other fields, this interaction should be taken care of inside the WinResource class, not in the nested class. The UnmanagedResourceWrapper works only as a wrapper for the handle and shouldn't contain other fields or methods, besides those shown in the above listing. The code in the WinResource class must coordinate all the resources being used, both managed and unmanaged ones, and must release all of them in its Dispose method. But if the client code omits to call the Dispose method, the destructor in the nested class will orderly release the unmanaged resource during the next garbage collection.

Let's see all the advantages of this simplified approach.

  • The requirement that you shouldn't access reference fields from inside the Finalize method is automatically satisfied, because the only field of the UnmanagedResourceWrapper type is a handle (a value type).
  • If the client code omits to invoke the WinResource.Dispose method before the WinResource object goes out of scope, the WinResource object is removed from the heap anyway at the first GC; only the few bytes used by the UnmanagedResourceWrapper object survive in the heap and will be promoted to generation 1 or 2. Therefore this technique is more efficient than writing a single finalizable object that allocates both managed and unmanaged resource.
  • The UnmanagedResourceWrapper class is private and you can't inherit from it, therefore you can mark it as sealed. This means that you never have to worry about the Dispose/Finalize pattern in derived classes - a topic on which tons of digital ink has been spilled. It is possible to inherit from WinResource as you'd do with disposable class, therefore there are no limitations in this respect. (It's exactly like when you inherit from other disposable classes such as FileStream.)
  • The UnmanagedResourceWrapper is private and nested in another type and it isn't possible to achieve a refernence to one of its instances; therefore, a client can't "resurrect" a UnmanagedResourceWrapper object during the finalization step, a technique that is rarely useful and often dangerous. (Even though I show in my Programming Visual Basic .NET book how you can use it to implement an object pool.)
  • The UnmanagedResourceWrapper constructor performs a single "atomic" action; if this action fails, the value of the handle is still qual to InvalidHandle, therefore the code in the Finalize method can detect this special value and do nothing in that case. There are only two cases: either the unmanaged resource has been correctly allocated or an exception prevented it from being created, and you don't have to worry about an object that has been built only partially because of an exception in its constructor.
  • Many other recommendations related to the Dispose/Finalize pattern become void, such as the one that dictates that you should neither write finalizers inside structures nor calling virtual methods from inside the finalizer. In fact, the UnmanagedResourceWrapper class is sealed and has no virtual methods. Nor do you have to worry about versioning issues.
  • Another advantage: the UnmanagedResourceWrapper class is so simple and generic that you can ofter reuse it as-is (or with minor edits) inside other classes, by means of a plain copy-and-paste action. Being a nested class, you don't even need to change its name to avoid name collisions.

I am sure that in some cases this simplified pattern can't be used, though it always worked well in my applications. I believe that it's quite odd that this simplified approach is rarely mentioned in articles and books on this topic.


Technical matters aside, I think that another kind of consideration about the Dispose/Finalize pattern is in order.

In my opinion, it is essential to put a lot of emphasis on the fact that the Dispose/Finalize pattern should be used only when your type invokes unmanaged code that allocates unmanaged resources (including unmanaged memory) and returns an handle that you must use eventually to release the resource. If the unmanaged resource is already wrapped by a .NET object (e.g. a FileStream or a SqlConnection) or a COM object, the .NET class that uses the resource must implement IDisposable, not the finalizer. And you must implement the Finalize method only if your code assigns the handle to a class-level field. If the handle is assigned to a local variable and the unmanaged resource is released before exiting the method - possibly in the Finally section of a Try block - you don't even have to implement the IDisposable interface. One of the few exceptions to this rule is when your managed code allocates unmanaged memory directly, by means of the System.Runtime.InteropServices.Marshal type.

I talked to many developers who believe that, in doubt, they should always implement the Finalize method, just in case. This is a common mistake. Defining a finalizable class without a real reason to do so can hurt performance, because the CLR takes slightly longer to allocate finalizable objects, because it has to register them in the f-reachable queue. And in the worst case - that is if the caller omits to call to the Dispose method - a finalizable object can have even more impact on performance, because it will be promoted to a higher generation without any real reason for such an overhead.

To recap: when do you really need to implement the Finalize method? Thinking of all the commercial apps I worked on in these years, I'd say that I used this pattern no more than 4 or 5 times. For sure, I used it more frequently in books and articles than in the real world. :-)

11/25/2005 10:37:38 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
 
Get RSS/Atom Feed
RSS 2.0 | Atom 1.0
Search in the blog
Archive
<February 2010>
SunMonTueWedThuFriSat
31123456
78910111213
14151617181920
21222324252627
28123456
78910111213
Categories

Powered by: newtelligence dasBlog 1.8.5223.1