用IDisposable清理Excel互操作对象

在我的公司中,发布Excel Interop对象的常用方法是使用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 

其中_xlApp是通过以下方式在构造函数中创build的:

 Try _xlApp = CType(GetObject(, "Excel.Application"), Excel.Application) Catch e As Exception _xlApp = CType(CreateObject("Excel.Application"), Excel.Application) End Try 

客户端使用using-statement来执行有关excel互操作对象的代码。

我们完全避免使用两点规则 。 现在我开始研究如何释放(Excel)互操作对象以及我发现的几乎所有讨论,比如如何正确清理Excel互操作对象或释放Excel对象 ,大多使用Marshal.ReleaseComObject(),但都不使用IDisposable接口。

我的问题是:使用IDisposable Interace发布excel互操作对象有什么缺点吗? 如果是这样,这些缺点是什么。

使用IDisposable Interace有什么缺点吗?

当然,它完全没有成就。 使用使用或调用Dispose()永远不是将variables设置为Nothing的适当方法。 这就是你的代码所做的一切。

我们完全避免使用两点规则。

随意继续无视它,这是无稽之谈,只会导致悲伤。 博客作者暗示的断言是,这样做会迫使程序员使用一个variables来存储xlApp.Workbooks的值。 所以他有一个战斗机会,以后,不要忘记调用releaseObject()。 但是还有更多的语句产生一个不使用点的接口引用。 像Range(x,y)那样,有一个隐藏的Range对象引用,你永远不会看到。 不得不把它们存储起来,只会产生令人难以置信的令人费解的代码。

而忽略一个就足以完全不能完成工作。 完全不可能debugging。 这是C程序员必须写的那种代码。 而且经常失败的时候,大的C程序往往会泄漏内存,程序员花费大量的时间来查找这些泄漏。 当然不是.NET的方式,它有一个垃圾收集器自动执行此操作。 它永远不会错。

麻烦的是,照顾这项工作有点慢。 非常多的devise。 没有人注意到这一点,除了这种代码。 你可以看到垃圾收集器没有运行,你仍然可以看到Office程序正在运行。 当你写xlapp.Quit()时,它并没有退出,它仍然存在于任务pipe理器的进程选项卡中。 当他们这样说的时候,他们想要发生的事情就是让它退出。

这在.NET中是非常有可能的,你当然可以迫使GC完成这项工作:

 GC.Collect() GC.WaitForPendingFinalizers() 

繁荣, 每个 Excel对象引用自动释放。 没有必要自己存储这些对象引用,并显式调用Marshal.ReleaseComObject(),CLR为你做。 它从来没有错,它不使用或需要一个“双点规则”,并没有find那些隐藏的接口引用返回。


然而,重要的是你放这个代码的地方。 而且大多数程序员把它放在错误的地方,使用那些Excel接口的方法。 这很好,但是在debugging代码的时候却不起作用,在这个答案中解释了一个怪癖。 在博客作者的代码中正确的做法是将代码移动到一个小帮助方法中,我们称之为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 

请记住,这确实只是一个debugging工件。 程序员只是不想使用任务pipe理器来杀死僵尸Excel.exe实例。 当他们停止debugging器时,Zombified,阻止程序正常退出,并收集垃圾。 这是正常的 。 当您的程序由于任何原因而停止生产时,也会发生这种情况。 把你的能量放在它所属的地方,从你的代码中得到错误,所以你的程序不会死。 GC不需要更多的帮助。

如果你正在寻找一个更干净的方式,你可以使用Koogra 。 这不是太多的额外开销(只有两个DLL你必须包括在你的refrences),你不必处理隐式垃圾收集。

下面的代码是从excel文件中读取10行10列所需的全部内容,而不留下EXCEL32Excel.exe进程。 我在一个月前曾经有过这个问题,并且写了一些关于如何去做的说明。 比直接处理Excel Interop更容易,更简单。

 Koogra.IWorkbook workbook = Koogra.WorkbookFactory.GetExcel2007Reader("MyExcelFile.xlsx"); Net.SourceForge.Koogra.IWorksheet worksheet = workbook.Worksheets.GetWorksheetByName("Sheet1"); //This will invididually print out to the Console the columns AJ (10 columns) for rows 1-10. for (uint rowIndex = 1; rowIndex <= 10; rowIndex++) { for (uint columnIndex = 1; columnIndex <= 10; columnIndex++) { Console.WriteLine(worksheet.Rows.GetRow(rowIndex).GetCell(columnIndex).GetFormattedValue()); } }