首先 - 您永远不必打电话Marshal.ReleaseComObject(...)
或Marshal.FinalReleaseComObject(...)
在进行 Excel 互操作时。这是一个令人困惑的反模式,但任何有关此的信息(包括来自 Microsoft 的)表明您必须从 .NET 手动释放 COM 引用都是不正确的。事实上,.NET 运行时和垃圾收集器正确地跟踪和清理 COM 引用。
其次,如果要确保在进程结束时清理对进程外 COM 对象的 COM 引用(以便 Excel 进程将关闭),则需要确保垃圾收集器运行。您可以通过调用GC.Collect()
和正确地做到这一点GC.WaitForPendingFinalizers()
。调用两次是安全的, end 确保循环也被清理干净。
第三,在调试器下运行时,局部引用会人为地保持活动状态,直到方法结束(这样局部变量检查才起作用)。因此,调用对于从同一方法GC.Collect()
中清除对象无效。rng.Cells
您应该将执行 COM 互操作的代码从 GC 清理中拆分为单独的方法。
一般模式是:
Sub WrapperThatCleansUp()
' NOTE: Don't call Excel objects in here...
' Debugger would keep alive until end, preventing GC cleanup
' Call a separate function that talks to Excel
DoTheWork()
' Now Let the GC clean up (twice, to clean up cycles too)
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
Sub DoTheWork()
Dim app As New Microsoft.Office.Interop.Excel.Application
Dim book As Microsoft.Office.Interop.Excel.Workbook = app.Workbooks.Add()
Dim worksheet As Microsoft.Office.Interop.Excel.Worksheet = book.Worksheets("Sheet1")
app.Visible = True
For i As Integer = 1 To 10
worksheet.Cells.Range("A" & i).Value = "Hello"
Next
book.Save()
book.Close()
app.Quit()
' NOTE: No calls the Marshal.ReleaseComObject() are ever needed
End Sub
关于这个问题有很多虚假信息和混淆,包括 MSDN 和 StackOverflow 上的许多帖子。
最终说服我仔细研究并找出正确建议的是这篇文章https://blogs.msdn.microsoft.com/visualstudio/2010/03/01/marshal-releasecomobject-considered-dangerous/以及找到在某些 StackOverflow 答案的调试器下,引用保持活动状态的问题。