真·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进程残留。

相关推荐
驱动小百科9 天前
如何在Windows上安装.NET Framework 详细教程分享
windows·.net·.net framework·.net安装·.net下载
张太行_9 天前
MySQL与Excel比较
数据库·mysql·excel
cwtlw9 天前
Excel学习03
笔记·学习·其他·excel
郭优秀的笔记9 天前
计算本地Excel某两列的差异值
excel
Kookoos10 天前
ABP vNext + Azure Application Insights:APM 监控与性能诊断最佳实践
后端·c#·.net·abp vnext
专注VB编程开发20年10 天前
asp.net core Razor动态语言编程代替asp.net .aspx更高级吗?
开发语言·后端·c#·asp.net·.net
安木夕10 天前
C#.Net筑基-优雅LINQ的查询艺术
c#·.net
涔溪10 天前
实现 el-table 中键盘方向键导航功能vue2+vue3(类似 Excel)
前端·vue.js·excel
追逐时光者10 天前
一套基于 .NET 开源的低代码、权限、工作流、动态接口平台
后端·.net