我在C#(ApplicationClass)中使用Excel互操作,并在finally子句中放置了以下代码:
while (System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet) != 0) { }
excelSheet = null;
GC.Collect();
GC.WaitForPendingFinalizers();
尽管这种方法有效,但即使在我关闭Excel之后,Excel.exe进程仍处于后台。它只在我的应用程序被手动关闭后发布。
我做错了什么,或者是否有其他方法可以确保正确处理互操作对象?
Excel不会退出,因为应用程序仍保留对COM对象的引用。
我猜您调用了COM对象的至少一个成员,而没有将其分配给变量。
对我来说,它是excelApp.Worksheets对象,我直接使用它,而没有将它分配给变量:
Worksheet sheet = excelApp.Worksheets.Open(...);
...
Marshal.ReleaseComObject(sheet);
我不知道C#在内部为WorksheetsCOM对象创建了一个包装器,但我的代码没有发布它(因为我不知道),这也是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互操作对象