首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用IDisposable清理Excel Interop对象

用IDisposable清理Excel Interop对象
EN

Stack Overflow用户
提问于 2014-08-05 16:12:53
回答 2查看 14.5K关注 0票数 42

在我的公司,释放Excel Interop对象的常用方法是使用IDisposable,方法如下:

代码语言:javascript
复制
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的方式如下:

代码语言:javascript
复制
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)互操作对象,我找到的几乎所有关于它的讨论,如How to properly clean up excel interop objectsRelease Excel Objects,都主要使用Marshal.ReleaseComObject(),没有一个使用IDisposable接口。

我的问题是:使用IDisposable接口发布excel interop对象有什么缺点吗?如果是这样,这些缺点是什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-08-05 17:43:13

使用IDisposable接口有什么缺点吗

当然,它什么也做不了。使用或调用Dispose()从来都不是将变量设置为空的合适方式。这就是你的代码所做的一切。

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

请随意继续忽略它,它是胡说八道,除了悲伤什么也没有。博客作者隐含的断言是,这样做会迫使程序员使用变量来存储xlApp.Workbooks的值。因此,稍后他将有机会不忘记调用releaseObject()。但是还有更多的语句生成不使用点的接口引用。像Range(x,y)一样,有一个隐藏的Range对象引用,你永远看不到它。不得不存储它们只会产生令人难以置信的令人费解的代码。

而忽略其中一个就足以完全无法完成工作。完全不可能调试。这是C程序员必须编写的代码。而且经常失败,大的C程序经常泄漏内存,他们的程序员花了大量的时间来寻找这些泄漏。当然不是.NET的方式,它有一个垃圾收集器来自动完成这项工作。它从来不会出错。

问题是,它在处理这项工作方面有点慢。很大程度上是设计出来的。没有人会注意到这一点,除了在这种代码中。您可以看到垃圾回收器没有运行,但您仍然看到Office程序正在运行。当您编写xlapp.Quit()时,它并没有退出,它仍然存在于任务管理器的进程选项卡中。他们想要发生的是,当他们这样说的时候,它就会退出。

在.NET中,这是非常可能的,您当然可以强制GC完成这项工作:

代码语言:javascript
复制
GC.Collect()
GC.WaitForPendingFinalizers()

突然,每个Excel对象引用都会自动释放。不需要自己存储这些对象引用并显式调用Marshal.ReleaseComObject(),CLR会为您做这件事。而且它永远不会出错,它不使用或不需要“两点规则”,并且可以毫不费力地找到那些隐藏的接口引用。

然而,最重要的是,确切地说,是您放置此代码的位置。大多数程序员把它放在错误的地方,放在使用那些Excel接口的相同方法中。这很好,但在调试代码时不起作用,this answer中解释了这一怪癖。在博客作者的代码中,正确的方法是将代码移到一个小帮助器方法中,我们称其为DoExcelThing()。如下所示:

代码语言:javascript
复制
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实例。当他们停止调试器时僵尸,阻止程序正常退出并收集垃圾。这很正常。当你的程序由于任何原因在生产中死亡时,也会发生这种情况。把你的精力放在它该用的地方,消除代码中的bug,这样你的程序就不会死。GC不需要更多的帮助。

票数 122
EN

Stack Overflow用户

发布于 2014-08-22 06:00:53

如果你正在寻找一种更干净的方式,你可以使用Koogra。它没有太多额外的开销(只需要在你的引用中包含两个dll),你也不必处理隐式的垃圾收集。

下面的代码就是在没有遗留任何EXCEL32Excel.exe进程的情况下从excel文件中读取10行10列所需的全部内容。我一个月前就遇到过这个问题,wrote instructions on how to do it.比直接使用Excel Interop更简单、更简洁。

代码语言:javascript
复制
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());
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25134024

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档