Before getting to know how to implement IDisposable, must has some basic about .NET system first.
Unmanaged Code, which means the code developed outside .NET Framework is known as unmanaged code. It's not run under CLR (Common Language Runtime) such as C++ can be used to write such applications , for examples, access low level functions of the operating system. It offers the powerful features that managed code does not, and might damaging as well. Unmanaged code can be unmanged source code and unmanaged compile code, and
unmanged code is execute with the help of wrapper classes, and caution is required (doesn't be executed by CLR). It will be compiled into machine code and executed by the OS directly.
Managed Code is the code that targets to common language runtime which is under foundation of .NET Framework. Managed Code will supply necessary things for CLR to provides services such as memory management, cross-language integration, handling security, lifetime control of objects, in short, it will look after your applications. All code based on IL (Intermediate Language) executes as managed code.
Garbage Collector will clean unused resources automatically, but can still call it explicitly. It will do finalizer in destructor of each object. The process of cleaning resources are done in a finalizer thread not a main thread.
Unmanaged Resources falls into two categories:
Unmanaged Resources falls into two categories:
- Resources that are wrapped in a managed class (ie Bitmap, Font etc) but still need Dispose to be called to clean them up property.
- Resources that you allocated that are representations of native resources (ie device contexts that need to be released)
The propose of using dispose is we want to free both kinds of unmanged resources. Note that for the first kind of unmanged resources, the garbage collector will take care of them when it have to clean them up. We only need to focus about true native resources that we have allocated (in case we have).
To finalize and dispose resources correctly, in .NET, we can just implement IDisposable interface into a class you want to add cleaning function. To sum up, the characteristics we needed are as followings issues:- Manage Dispose from calling by users and garbage collector separately.
- Implements IDisposable interface that contains Dispose() method.
- Dispose can be called multiple times without any problem.
- Can release unmanaged resources properly.
- In case programmer fails to call dispose, it still can clean resources in the right way.
From the requirements, it's easy to solve the first bullet by implement Dispose(bool) which use bool to separate call by users and garbage collector to do the different ways in cleaning resources. For the second bullet we could just create dispose function inherited from interface, and let's its body call Dispose(bool) function. Moreover, we can use extra private property to indicate the resources are already disposed or not, and we have to include the ways to release unmanged resources in Dispose(bool) also. Finally, to prevent failure to release resources when users forget to call dispose, we could just create destructor of that class that its body will call Dispose(bool) too.
For example, The following is a mock up class that implements IDisposable:
class Resource : IDisposable { private bool IsDisposed { get; set; } ~Resource() { // Finalizer (GC) calls Dispose(false) Dispose(false); } // Explicitly Call Dispose(true), called by users public void Dispose() { Dispose(true); // Suppress from being called again by GC GC.SuppressFinalize(this); } // The bulk of the clean-up code is implemented in Dispose(bool) protected virtual void Dispose(bool disposing) { // Check is it already disposed if (!IsDisposed) { // When dispose is explicitly called (main thread) if (disposing) { // Free wrapped unmanaged resources in managed class // They are automatically cleaned by GC if it still not disposed } // Free native resources if there are any. IsDisposed = true; } } }
The reason why Dispose(bool) is a protected member because this method will be an internal control for freeing resources of this class and its sub classes, so it should not be seen by other classes else.
This post is a summary that I have faced this problem myself, and there are many styles to solve this problem that have a little different in details, but their concept are still the same. For this post I try to sum up this problem in short. This post may be too long and hard to read, so I added references in case you want to know more details about anything I found for this post. I hope it will help you understand how to implement dispose properly and know its reasons and mechanism of how it works ^^.
References:
No comments:
Post a Comment