Поскольку мое взаимодействие с C# в Excel стало более изощренным, у меня начали работать безголовые копии объектов Microsoft Office Excel (32-разрядная версия) в Диспетчере задач после того, как я закрыл свое приложение. Я не нашел никакой комбинации voodoo Marshal.ReleaseComObject () и G C .Collect (), которая бы полностью их устраняла. Я наконец удалил весь код вуду и последовал совету Ханса Пассента. Я смог завершить их в большинстве случаев, когда приложение закрывалось по следующей схеме:
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# finally)? ). Одно заметное исключение происходит, когда вы прерываете приложение из отладчика VS (Shift-F5 или красный квадрат «Stop Debugging» на панели инструментов). Если вы прерываете приложение из отладчика, предложение finally не выполняет , а , и объект Excel остается запущенным. Это прискорбно, но я не нашел способа обойти это.
Я проверил это в Visual Studio 2019 и. NET Framework 4.7.2 с использованием взаимодействия Excel 2007 и Excel 2016.