This question is about dealing with unmanaged resources (COM interop) and making sure there won't be any resource leaks. I'd appreciate feedback on whether I seem to do things the right way.
Background:
Let's say I've got two classes:
A class
LimitedComResource
which is a wrapper around a COM object (received via some API). There can only be a limited number of those COM objects, therefore my class implements theIDisposable
interface which will be responsible for releasing a COM object when it's no longer needed.Objects of another type
ManagedObject
are temporarily created to perform some work on aLimitedComResource
. They are notIDisposable
.
To summarize the above in a diagram, my classes might look like this:
+---------------+ +--------------------+
| ManagedObject | <>------> | LimitedComResource |
+---------------+ +--------------------+
|
o IDisposable
(I'll provide example code for these two classes in just a moment.)
Question:
Since my temporary ManagedObject
objects are not disposable, I obviously have no control over how long they'll be around. However, in the meantime I might have Dispose
d the LimitedComObject
that a ManagedObject
is referring to. How can I make sure that a ManagedObject
won't access a LimitedComResource
that's no longer there?
+---------------+ +--------------------+
| managedObject | <>------> | (dead object) |
+---------------+ +--------------------+
I've currently implemented this with a mix of weak references and a flag in LimitedResource
which signals whether an object has already been disposed. Is there any better way?
Example code (what I've currently got):
LimitedComResource
:
class LimitedComResource : IDisposable
{
private readonly IUnknown comObject; // <-- set in constructor
...
void Dispose(bool notFromFinalizer)
{
if (!this.isDisposed)
{
Marshal.FinalReleaseComObject(comObject);
}
this.isDisposed = true;
}
internal bool isDisposed = false;
}
ManagedObject
:
class ManagedObject
{
private readonly WeakReference limitedComResource; // <-- set in constructor
...
public void DoSomeWork()
{
if (!limitedComResource.IsAlive())
{
throw new ObjectDisposedException();
// ^^^^^^^^^^^^^^^^^^^^^^^
// is there a more suitable exception class?
}
var ur = (LimitedComResource)limitedComResource.Target;
if (ur.isDisposed)
{
throw new ObjectDisposedException();
}
... // <-- do something sensible here!
}
}