First, I agree that I suggest having a finalizer as a backup, but I try to ensure that it is never called by explicitly calling myClass.Dispose or through "use".
eg.
var myClass = new MyClass() try { //do stuff } finally { myClass.Dispose(); }
or
using (var myClass = new MyClass()) {
Marshall.ReleaseComObject
If you use a lot of COM objects, I also suggest that you use Mashall.ReleaseComObject (comObj) to explicitly clear RCW links.
So, code like this is offered elsewhere:
if (comInstance != null) { comInstance.FreeStuff(); comInstance = null; }
will become:
if (comInstance != null) { comInstance.FreeStuff(); int count = Marshall.ReleaseComObject(comInstance); if (count != 0) { Debug.Assert(false, "comInstance count = " + count); Marshal.FinalReleaseComObject(comInstance); } comInstance = null; }
When checking the return value, ReleaseComObject () is not strictly necessary; I like to check it to make sure everything is increasing or decreasing as expected.
Two dot rule
If you decide to use this, something you need to know about is that, for the proper release of your COM objects, code refactoring may be required. In particular, this is what I call a two-dot rule. Any line using COM objects containing 2 points requires close attention. For example,
var name = myComObject.Address.Name;
In this statement, we get a reference to the Address COM object, increasing its number of references to RCW, but we have no way to call ReleaseComObject. The best way to do this is to break it (try ... for clarification).
var address = myComObject.Address; var name = address.Name; MyReleaseComObject(address);
where MyReleaseComObject is a utility method that completes my check on count and FinalReleaseComObject () on top.