使用IDisposable清理Excel Interop对象

rue*_*edi 25 .net vb.net excel interop com-interop

在我的公司中,发布Excel Interop Objects的常用方法是使用IDisposable,方法如下:

Public Sub Dispose() Implements IDisposable.Dispose
    If Not bolDisposed Then
        Finalize()
        System.GC.SuppressFinalize(Me)
    End If
End Sub

Protected Overrides Sub Finalize()
    _xlApp = Nothing
    bolDisposed = True
    MyBase.Finalize()
End Sub
Run Code Online (Sandbox Code Playgroud)

IDisposable构造函数中以下列方式创建的位置:

Try
    _xlApp = CType(GetObject(, "Excel.Application"), Excel.Application)
Catch e As Exception
    _xlApp = CType(CreateObject("Excel.Application"), Excel.Application) 
End Try
Run Code Online (Sandbox Code Playgroud)

并且客户端使用_xlApp执行有关excel互操作对象的代码.

我们完全避免使用双点规则.现在我开始研究如何重新发布(Excel)互操作对象以及我发现的几乎所有关于它的讨论如何正确清理excel互操作对象释放Excel对象主要使用Marshal.ReleaseComObject(),它们都没有使用IDisposable接口.

我的问题是:使用IDisposable Interace释放excel互操作对象有什么缺点吗?如果是这样,这些不利因素是什么.

Han*_*ant 77

使用IDisposable Interace是否有任何缺点

当然,它完全没有任何成就.使用使用或调用Dispose()是从来没有设置为Nothing变量的适当方式.这就是你的代码所做的一切.

我们完全避免使用双点规则.

随意忽略它,这是无稽之谈,只会导致悲伤.博客作者隐含的断言是,这样做会迫使程序员使用变量来存储xlApp.Workbooks的值.所以他有一个战斗的机会,以后,不要忘记调用releaseObject().但是还有更多语句产生不使用点的接口引用.像Range(x,y)之类的东西,那里有一个你永远不会看到的隐藏的Range对象引用.必须存储它们只会产生令人难以置信的错综复杂的代码.

而忽视一个就足以完全无法完成工作.完全不可能调试.这是C程序员必须编写的代码.并且经常失败,大型C程序经常泄漏内存,他们的程序员花费大量时间来发现这些泄漏.当然不是.NET方式,它有一个垃圾收集器来自动执行此操作.它从来没有错.

麻烦的是,照顾这份工作有点慢.很多设计.除了这种代码之外,没有人注意到这一点.您可以看到垃圾收集器没有运行,您仍然看到Office程序正在运行.当你编写xlapp.Quit()时它没有退出,它仍然出现在任务管理器的进程选项卡中.他们想要发生的是当他们这么说时就退出.

这在.NET中很有可能,你当然可以强制GC完成工作:

GC.Collect()
GC.WaitForPendingFinalizers()
Run Code Online (Sandbox Code Playgroud)

Boom,每个 Excel对象引用都会自动释放.不需要自己存储这些对象引用并显式调用Marshal.ReleaseComObject(),CLR会为您执行此操作.它永远不会出错,它不使用或需要"双点规则",它可以毫无困难地找回那些隐藏的接口引用.


然而,重要的是您放置此代码的确切位置.并且大多数程序员使用这些Excel接口的方法将它放在错误的位置.哪个很好,但在调试代码时不起作用,这个问题本答案中有所解释.在博客作者的代码中执行此操作的正确方法是将代码移动到一个小帮助方法,让我们称之为DoExcelThing().像这样:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    DoExcelThing()
    GC.Collect()
    GC.WaitForPendingFinalizers()
    '' Excel.exe no longer running anymore at this point
End Sub
Run Code Online (Sandbox Code Playgroud)

并且请记住,这确实只是一个调试工件.程序员只是不得不使用任务管理器来杀死僵尸Excel.exe实例.当他们停止调试器时僵尸化,阻止程序正常退出并收集垃圾.这很正常.当你的程序因任何原因在生产中死亡时,也会发生这种情况.把你的精力放在它所属的地方,从你的代码中获取错误,这样你的程序就不会死亡.GC不需要更多的帮助.

  • 阿门!请继续打击已经感染互联网的整个两点,即ReleaseComObject voodoo垃圾(以及指向调试怪癖的+1). (10认同)
  • 初读这篇文章时,我错过了应该在哪里放置GC.Collect()命令的部分。将其放置在正确的位置后,它可以完美运行。 (3认同)
  • 感谢您澄清无二点的Marshal.ReleaseComObject样式对于执行Excel(或我认为大多数其他COM)Interop仍然是必需的,并且仍会发布引用。我已经听到了很多有关它的信息,我担心我将不得不重写代码库的大部分内容。。。 (2认同)
  • 整个[RCW设计](http://blogs.msdn.com/b/yvesdolc/archive/2004/07/21/190691.aspx)已经是“死马”了(https://en.wikipedia.org / wiki / Flogging_a_dead_horse)。未来将是一个自动生成的C ++ / CLI包装程序集(增强的互操作程序集),无论您“处置”它还是将其留给GC,它都将正确释放。错误的设计是导致每个C#Office自动化不稳定,导致每个人都从COM中失控,最终导致每个人都从Office套件本身失控的原因。为时已晚,已经发生了。 (2认同)