[英]How do I properly clean up Excel interop objects from an C# application?
這個問題已經被問過和回答過很多次了,例如:
如何正確配置 Interop Excel 應用程序和工作簿?
為什么 Microsoft.Office.Interop.Excel.Application.Quit() 讓后台進程運行?
但是 Hans Passent 對以下問題的回答讓我相信它們已經過時和/或完全不正確:
所以,我的問題是:如何清理我的 Excel 互操作對象,以便及時釋放所有托管和非托管 Excel 資源(即,當內存壓力觸發垃圾回收時)?
在發布模式下:
僅僅讓所有托管 Excel 互操作對象超出范圍就足夠了嗎?
我還需要調用 excelApp.Quit() 嗎?
非托管堆上的內存壓力會觸發垃圾回收嗎? 即我還需要打電話:
GC.Collect();
GC.WaitForPendingFinalizers();
確保我的托管應用程序不會耗盡內存? 我是否需要調用:System.Runtime.InteropServices.Marshal.FinalReleaseComObject(managedExcelObject)?
請不要回答這個問題,除非您已經閱讀並理解了 Hans Passent 的回答。
隨着我對 C# Excel 互操作的使用變得更加復雜,在我關閉應用程序后,我開始在任務管理器中運行“Microsoft Office Excel(32 位)”對象的無頭副本。 我發現沒有巫毒 Marshal.ReleaseComObject() 和 GC.Collect() 的組合可以完全消除它們。 我最終刪除了所有巫毒教代碼並遵循了 Hans Passent 的建議。 在大多數情況下,當應用程序關閉時,我可以使用以下模式終止它們:
using System;
using System.IO;
using excel = Microsoft.Office.Interop.Excel;
namespace ExcelInterop {
static class Program {
// Create only one instance of excel.Application(). More instances create more Excel objects in Task Manager.
static excel.Application ExcelApp { get; set; } = new excel.Application();
[STAThread]
static int Main() {
try {
ExcelRunner excelRunner = new ExcelRunner(ExcelApp)
// do your Excel interop activities in your excelRunner class here
// excelRunner MUST be out-of-scope when the finally clause executes
excelRunner = null; // not really necessary but kills the only reference to excelRunner
} catch (Exception e) {
// A catch block is required to ensure that the finally block excutes after an unhandled exception
// see: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally
Console.WriteLine($"ExcelRunner terminated with unhandled Exception: '{e.Message}'");
return -1;
} finally {
// this must not execute until all objects derived from 'ExcelApp' are out of scope
if (ExcelApp != null) {
ExcelApp.Quit();
ExcelApp = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
Console.WriteLine("ExcelRunner terminated normally");
return 0;
}
}
}
在我的 ExcelRunner 課程中,我將數百個 csv 文件讀入 excel 工作簿,並創建了數十個帶有表格和圖表的 .xlsx 文件。 我只創建了 Microsoft.Office.Interop.Excel.Application() 的一個實例並一遍又一遍地重用它。 更多實例意味着在任務管理器中運行的更多“Microsoft Office Excel”對象需要清理。
請注意,必須執行 finally 子句才能擺脫無頭 Excel 對象。 上面的模式處理大多數應用程序關閉情況(包括由未處理的異常引起的大多數中止 - 但請參閱是否 C#“最終”阻止始終執行? )。 當您從 VS 調試器(Shift-F5 或工具欄上的紅色“停止調試”方塊)中止應用程序時,會發生一個值得注意的異常。 如果您在調試器中止程序,最終條文不執行和Excel對象是左捉迷藏。 這是不幸的,但我沒有找到解決方法。
我使用 Excel 2007 互操作和 Excel 2016 互操作在 Visual Studio 2019 和 .NET Framework 4.7.2 中對此進行了測試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.