views:

560

answers:

2

C++/CLI helpfully generates the IDisposable scaffolding for you when you implement a destructor on a ref class. Also, if you don't implement a destructor, but your class has a member variable which implements IDisposable, then IDisposable is again automatically implemented on your class. It's pretty helpful and much better than how IDisposable is handled in C#.

I have run into this behaviour when implementing a ref class that holds onto an msclr::com::ptr (a smart pointer that contains an RCW).

ref class Test /* : IDisposable added by the compiler */
{
  msclr::com::ptr<IWhatever> _aComObject;
}

In my specific case, the COM object referenced by my class doesn't 'lock' some unmanaged resource, it effectively just uses up a bit of unmanaged memory that the CLR can't see. Therefore I would like to avoid confusing the users of my ref class by not implementing IDisposable the class. Instead I want to make the CLR aware of the existence of the COM object by using the GC API to add the appropriate memory pressure.

So, the question is: is there a way to suppress implementation of IDisposable on a ref class that doesn't implement a destructor, but does hold an IDisposable member variable?

NB: often this would be the wrong thing to do, as it would prevent users of the class from deterministically disposing of the underlying COM object, but given the particular circumstances, exposing IDisposable has the potential to confuse users of my ref class, since it really is not necessary to Dispose of the ref class in question.

I suppose one option would be to implement a variant of msclr::com::ptr without a destructor.

Any other method to suppress the automatic addition of IDisposable would be appreciated. Thanks.


Answer

Declare _aComObject as a handle to an msclr::com::ptr (msclr::com::ptr<IWhatever>^). The compiler does not then regard Test as being the 'owner' of the com ptr object, and does not Dispose it when Test is deleted.

A: 

I'm not sure I agree with the ratioanle for avoiding the IDispose implementation -- but why not just store an IWhatever* in your class. The compiler shouldn't then generate the IDisposable implementation.

If you don't want the destructor behaviour then what benefit is the com::ptr wrapper buying you? You can always declare an com::ptr on the stack and assign your member pointer to it in any given method if you really need it.

Rob Walker
I think you're getting confused between IDisposable and garbage collection. msclr::com::ptr will release the COM ref when GC'd, whereas holding a native COM pointer wont achieve that result without a good deal more work (re-implementing RCWs, effectively).
mackenir
(Or more correctly, the RCW can be collected when it's no longer reachable, releasing the COM reference)
mackenir
+1  A: 

I think the answer is to hold a handle to the msclr::com::ptr rather than holding it 'by value' (which is still holding it as a handle 'behind the scenes', except the C++CLI compiler treats it as a value - 'deleting' it (calling Dispose) when the owner object is deleted (Disposed)).

mackenir