使用IDisposable清理Excel Interop对象

时间:2014-08-05 08:12:53

标签: .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

其中_xlApp在构造函数中以下列方式创建:

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

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

我们完全避免使用two dot rule。现在我开始研究如何重新发布(Excel)Interop对象,几乎我发现的所有关于它的讨论,如How to properly clean up excel interop objectsRelease Excel Objects主要使用Marshal.ReleaseComObject(),它们都没有使用IDisposable接口。

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

2 个答案:

答案 0 :(得分:61)

  

使用IDisposable Interace

是否有任何缺点

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

  

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

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

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

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

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

GC.Collect()
GC.WaitForPendingFinalizers()

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


然而,重要的是完全您放置此代码的位置。并且大多数程序员使用这些Excel接口的方法将它放在错误的位置。哪个很好,但在调试代码时不起作用,这是this answer中解释的一个怪癖。在博客作者的代码中执行此操作的正确方法是将代码移动到一个小帮助方法,让我们称之为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

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

答案 1 :(得分:1)

如果您正在寻找更清洁的方式,可以使用Koogra。这不是额外的开销(只需要两个dll就必须包含在你的参考中)并且你不必处理隐式垃圾收集。

下面的代码是从excel文件读取10行10列所需的全部内容,但没有留下 EXCEL32 Excel.exe 进程。我在一个月前遇到过这个问题而且wrote instructions on how to do it.比直接处理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 A-J (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());
    }
}