我正在编写一个围绕 DirectSound 的托管包装器。(这是一个简单的部分包装器,它解决了我的特定问题,仅此而已。不要告诉我有关 NAudio 或其他什么的事情。) 包装 IDirectSound8 的托管类应该是 IDisposable 吗?为什么?关于 IDirectSoundBuffer8 的相同问题。
1 回答
从技术上讲:是的。实际上:没有。IDirectSound8 是一个 COM 接口,它们非常方便地包装在带有互操作库的 .NET 中。一个RCW。该 RCW 管理底层 COM coclass 对象的引用计数。RCW 不实现IDisposable,即使它非常依赖于非托管资源。
它不这样做的原因是因为几乎不可能正确实现 IDisposable。COM coclass 实现多个接口,创建一个会增加引用计数。在 dispose 安全之前,您必须 100% 确定所有这些接口指针都不再使用。这很难做到,这些指针是以意想不到的方式创建的。就像使用其中一个接口的索引属性一样,中间接口指针在您的代码中永远不可见。
这不是一个真正的问题,垃圾收集器负责引用计数,终结器完成工作。只是对象被释放需要更长的时间。标准 GC 行为。不幸的是,进程外 COM 服务器具有可观察到的副作用,当他们的代码停止使用接口时,当进程没有从 TaskMgr 进程列表中消失时,程序员往往会感到恼火。这里和论坛上有很多很多“Excel/Word 无法退出”的问题。
如果你想实现它,那么你可以通过在 Dispose() 实现中调用 Marshal.FinalReleaseComObject() 来实现。请注意失败的风险显着增加,错误的调用会导致很难诊断失败。与在本机代码中删除对象并仍然具有指向它的指针完全不同。如果它实际上是一个必须立即释放的“重”对象,那么 GC.Collect() + GC.WaitForPendingFinalizers() 也可以完成工作,而且出错的风险要小得多。当然有副作用。