我在vba中开发office解决方案已经有一段时间了,对vba中的office开发有了比较全面的了解。我已经决定是时候学习一些真正的.net编程了,现在有一些初期的问题。
在浏览了大量文章和论坛(这里和其他地方)之后,在使用COM对象时,似乎有一些关于.NET内存管理的混合信息。
有人说我应该总是果断地释放com对象,还有人说我几乎不应该这样做。
人们说我应该这么做:
The book 'Professional Excel Development'第861页。
This stack exchange question的回答是“必须释放对com对象的每个引用。如果你不这样做,这个过程将留在记忆中。”
建议用它来解决他的问题。
人们说我不应该这么做:
This blogstates“在vsto场景中,您通常不必使用releasecomObject。”
This MSDN blog by Eric Carter由eric carter合著,似乎没有提到内存管理或释放对象。
The book 'VSTO for Office 2007'说不要这样做。
有人提出了各种各样的建议:
This MSDN blog by Paul Harrington说我应该总是在不离开方法作用域的COM对象上执行此操作。如果COM对象离开了方法作用域,那么就忘掉它。为什么我不能一直忘记呢?
保罗·哈灵顿的博客似乎表明,微软的建议在过去的某个时候发生了变化。调用ReleaseComObject曾经是最佳实践,但现在已经不是这样了吗?我能把内存管理的细节留给ms,并假设一切都会很好吗?
最佳答案
我试图在我的interop开发中遵守以下关于ReleaseComObject
的规则。
如果我的托管对象实现了某种类似于IDisposable
的关闭协议,我将对我所引用的任何子com对象调用ReleaseComObject
。我所说的关机协议的一些例子:IObjectWithSite.SetSite(null)
IOleObject.SetClientSite(null)
IOleObject.Close()
IDTExtensibility2.OnDisconnection
IDTExtensibility2.OnBeginShutdown
IDisposable.Dispose
本身
这有助于打破.NET和本机COM对象之间的潜在循环引用,因此托管垃圾收集器可以无障碍地完成其工作。
也许,在您的vsto互操作场景中也可以使用类似的东西(afair,IDTExtensibility2
与此相关)。
如果Interop场景涉及IPC COM调用(例如,当您将托管事件接收器对象传递给进程外COM服务器(如Excel)时),则有另一个选项可跟踪对托管对象的外部引用:IExternalConnection
interface。IExternalConnection::AddConnection
/ReleaseConnection
与IUnknown::AddRef
/Release
非常相似,但是当从另一个com设备(包括居住在不同进程中的公寓)添加引用时,它们会被调用。IExternalConnection
为进程外场景提供了一种实现几乎通用的关闭机制的方法。当外部引用计数达到零时,您应该对可能包含引用的任何外部excel对象调用ReleaseComObject
,从而有效地中断进程与excel进程之间的任何潜在循环com引用。也许,类似这样的东西已经由vsto运行时实现了(我对vsto没有太多经验)。
也就是说,如果没有明确的关闭机制,我不会调用ReleaseComObject
。而且,我从不使用FinalReleaseComObject
。