真·VB.NET彻底释放Interop.Excel对象

使用 Microsoft.Office.Interop.Excel 虽然有速度慢的缺点;但是作为自带引用,兼容性最好,而且是COM对象模型也很熟悉(Excel里直接录个宏,很方便把VBA代码转成VB.NET)。所以处理几百上千条的小数据时还是很方便的。

Microsoft.Office.Interop.Excel 用得不多的最大问题其实就是拿简单例子可以正确释放Excel,做了大量操作后却发现在任务管理器中依然有多余Excel进程存在。

问题原因当然是COM对象映射到Interop交互对象之后,.NET下的交互对象释放次序不符合COM对象预期,导致不能正确释放。比如

vbnet 复制代码
Dim xlApp New Excel.Application() With {.Visible = False}
Dim xlWorkbooks As Excel.Workbooks = xlApp.Workbooks
Dim xlWorkbook As Excel.Workbook = xlWorkbooks.Open("...")

Dim value As Object = xlWorkbook.Sheets(1).Cells(1,1).Value

xlWorkbook.Close()
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkbook)
xlWorkbook = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkbooks)
xlWorkbooks = Nothing
xlApp.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp)
xlApp = Nothing
System.GC.Collect()

中间取value这行代码看起来很正常,没有保留任何交互对象。其实在整个对象访问路径上隐式使用了以下交互对象,要靠GC来释放(通常是延后的------------即调用Close()时交互对象未释放、工作簿关闭不了,之后的Quit()Excel不会退出),

vbnet 复制代码
xlWorkbook.Sheets 'Excel.Sheets
xlWorkbook.Sheets(1) 'Excel.Worksheet
xlWorkbook.Sheets(1).Cells 'Excel.Range
xlWorkbook.Sheets(1).Cells(1,1) 'Excel.Range

要做到正确释放,要把这些交互对象全部在Close()前释放。为了方便使用,把 Excel.ApplicationExcel.Workbook 封装在类中,用 IDisposable 接口确保释放。用类似下面的属性封装访问

vbnet 复制代码
    Public Property CellValue(sheetIndex As Object, rowNo As Integer, colNo As Integer) As Object
        Get
            Dim xlSheets As Excel.Sheets = m_xlWorkbook.Sheets
            Dim xlSheet As Excel.Worksheet = xlSheets.Item(sheetIndex)
            Dim xlCells As Excel.Range = xlSheet.Cells
            Dim xlCell As Excel.Range = xlCells.Item(rowNo, colNo)
            Dim value As Object = xlCell.Value
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlCell)
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlCells)
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheet)
            System.Runtime.InteropServices.Marshal.ReleaseComObject(xlSheets)
            System.GC.Collect(0)
            Return value
        End Get
        Set(value As Object)
            ' 同理所有交互对象保留变量、释放
        End Set
    End Property

上面的属性是通过行号、列号访问单元value;如果需要通过A1格式访问单元又要定义属性;如果需要访问单元text也要单独定义属性。
总之全部封装好后,读写完Excel文件后就能正确释放,不再有多余Excel进程残留。

相关推荐
忘忧记1 小时前
Excel VLOOKUP函数完全教程:从基础到高级实战
excel
葡萄城技术团队1 小时前
突破Excel局限!SpreadJS让电子表格“活”起来
java·数据库·excel
关关长语1 小时前
(一) Dotnet使用MCP的Csharp SDK
网络·.net·mcp
左师佑图3 小时前
Apache POI SXSSFWorkbook 报错“没有那个文件或目录”问题排查与解决方案
java·apache·excel
monkeyhlj6 小时前
excel-mcp-server rocky linux简单部署
linux·运维·excel
喵叔哟8 小时前
7. 从0到上线:.NET 8 + ML.NET LTR 智能类目匹配实战--反馈存储与数据治理:MongoDB 设计与运维
运维·mongodb·.net
.NET修仙日记9 小时前
SQL Server实战指南:从基础CRUD到高并发处理的完整面试题库
面试·职场和发展·c#·.net·sql server·.net全栈经典面试题库
lijingguang11 小时前
excel和word文件默认用office打开而不是用wps
word·excel·wps
xurime12 小时前
Excelize 开源基础库发布 2.10.0 版本更新
golang·开源·github·excel·ai编程·go语言
weixin_4569042721 小时前
基于.NET Framework 4.0的串口通信
开发语言·c#·.net