Working with resources is covered in Chapter 11, “Memory Management and Pointers,” both implementing the IDisposable interface and implementing a finalizer. How this looks in C++/CLI and Visual Basic is covered in this section.
For freeing resources, the interface IDisposable defines the Dispose() method. Using C# and Visual Basic, you have to implement the interface IDisposable. With C++/CLI the interface IDisposable is implemented as well, but this is done by the compiler if you just write a destructor.
// C# public class Resource : IDisposable { public void Dispose() { // release resource } } // C++/CLI public ref class Resource { public: ~Resource() { // release resource } }; ' Visual Basic Public Class Resource Implements IDisposable Public Sub Dispose() Implements IDisposable.Dispose ' release resource End Sub End Class
Important | With C++/CLI the Dispose method is invoked by using the delete statement. |
The C# using statement implements an acquire/use/release pattern to release a resource as soon as it is no longer used, even in the case of an exception. The compiler creates a try/finally statement and invokes the Dispose method inside the finally. Version 9 of Visual Basic supports the using statement similarly to C#. C++/CLI has an even more elegant approach to this problem. If a reference type is declared locally, the compiler creates a try/finally statement to invoke the Dispose() method at the end of the block.
// C# using (Resource r = new Resource()) { r.Foo(); } // C++/CLI { Resource r; r.Foo(); } ' Visual Basic Using r As New Resource r.Foo() End Using
If a class contains native resources that must be freed, the class must override the Finalize() method from the Object class. With C# this is done by writing a destructor. C++/CLI has a special syntax with the ! prefix to define a finalizer. Within a finalizer it is not allowed to dispose contained objects that have a finalizer as well because the order of finalization is not guaranteed. That’s why the Dispose pattern defines an additional Dispose() method with a Boolean parameter. With C++/CLI, it is not necessary to implement this pattern in the code because this is done by the compiler. The C++/CLI destructor implements both Dispose() methods. With Visual Basic, both Dispose() and the finalizer must be implemented manually. However, most Visual Basic classes are not using native resources directly, just with the help of other classes. With Visual Basic, usually it is not necessary to override the Finalize() method, but an implementation of the Dispose() method is often required.
Remember this important difference with destructors of C# and C++/CLI:
Important | Writing a destructor with C# overrides the Finalize() method of the base class. A C++/CLI destructor implements the IDisposable interface. |
// C# public class Resource : IDisposable { ~Resource // override Finalize { Dispose(false); } protected virtual void Dispose(bool disposing) { if (disposing) // dispose embedded members { } // release resources of this class GC.SuppressFinalize(this); } public void Dispose() { Dispose(true); } } // C++/CLI public ref class Resource { public: ~Resource() // implement IDisposable { this->!Resource(); } !Resource() // override Finalize { // release resource } }; ' Visual Basic Public Class Resource Implements IDisposable Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub Protected Overridable Sub Dispose(ByVal disposing) If disposing Then ' Release embedded resources End If ' Release resources of this class End Sub Protected Overrides Sub Finalize() Try Dispose(False) Finally MyBase.Finalize() End Try End Sub End Class