小编典典

如何正确清理 Excel 互操作对象?

all

我在 C# ( ApplicationClass) 中使用 Excel 互操作,并在 finally 子句中放置了以下代码:

while (System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet) != 0) { }
excelSheet = null;
GC.Collect();
GC.WaitForPendingFinalizers();

尽管这种方法有效,但Excel.exe即使在我关闭 Excel 后,该过程仍在后台。只有在我的应用程序手动关闭后才会发布。

我做错了什么,或者是否有其他方法可以确保正确处理互操作对象?


阅读 116

收藏
2022-03-02

共1个答案

小编典典

Excel 不会退出,因为您的应用程序仍持有对 COM 对象的引用。

我猜您正在调用 COM 对象的至少一个成员,而没有将其分配给变量。

对我来说,这是我直接使用的 excelApp.Worksheets 对象,而没有将其分配给变量:

Worksheet sheet = excelApp.Worksheets.Open(...);
...
Marshal.ReleaseComObject(sheet);

我不知道内部 C# 为 Worksheets COM 对象创建了一个包装器,该包装器没有被我的代码释放(因为我不知道它),这也是 Excel
没有被卸载的原因。

我在这个页面上找到了我的问题的解决方案,它也有一个很好的规则,用于在
C# 中使用 COM 对象:

切勿对 COM 对象使用两个点。


因此,有了这些知识,执行上述操作的正确方法是:

Worksheets sheets = excelApp.Worksheets; // <-- The important part
Worksheet sheet = sheets.Open(...);
...
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(sheet);

验尸后更新:

我希望每位读者都非常仔细地阅读 Hans Passant
的这个答案,因为它解释了我和许多其他开发人员偶然发现的陷阱。当我几年前写这个答案时,我不知道调试器对垃圾收集器的影响并得出了错误的结论。为了历史,我保持我的答案不变,但请阅读此链接并且
不要 走“两个点”的方式:了解 .NET
中的垃圾收集
使用 IDisposable 清理 Excel
互操作对象

2022-03-02