真·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.Application 和 Excel.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进程残留。

相关推荐
程序员清风16 分钟前
CSV、Excel 与数据库数据读取实践
数据库·oracle·excel
xiangcns24 分钟前
PDMS PiplineTool(三十)一堆小优化+一个彩蛋功能
.net·二次开发·pdms
泡海椒4 小时前
JQuick-Excel JContext 与 trans 实战:将字典值带入行转换
excel
EatFan7 小时前
MCP 从概念到落地:Java(Spring AI Alibaba)与 .NET 双栈接入实操对比
java·人工智能·后端·spring·.net·java后端·mcp
泡海椒1 天前
JQuick-Excel dateFormat 转换实战:日期值与 FORMAT 显示格式的边界
开发语言·python·excel
2501_933670791 天前
2027风控策略岗秋招准备:SQL、Excel、建模的优先级与项目路径
人工智能·sql·excel
流形填表1 天前
在线考试平台导入题库:Excel格式与字段对照
excel
CSharp精选营1 天前
.NET 面试必问的 8 道 GC 题,建议收藏
.net·面试题·gc·c#面试题
开开心心就好2 天前
办公软件卸载不干净?专用工具一键清残留
java·前端·人工智能·智能手机·kafka·excel·memcache
全速向光2 天前
Excel函数系列09:公式又长又乱?LET+LAMBDA+MAP+REDUCE,自定义函数一次讲透
excel