Имеет ли значение, что COM-объект, не назначенный для var, не освобожден?

Будут ли освобождены все неуправляемые объекты COM в случае, если я использую такой код

var worksheet = new Application().Workbooks.Add().Worksheets.Add();
Marshal.ReleaseComObject(worksheet);

вместо такого кода

var excel = new Application();
var workbook = excel.Workbooks.Add();
var worksheet = workbook.Worksheets.Add();
Marshal.ReleaseComObject(excel);
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(worksheet);

?

Если есть какая-то документация, пожалуйста, отправьте ссылку в ответ.

1 ответ

На самом деле, оба примера кода оставят процесс Excel запущенным в фоновом режиме. Вам нужно позвонить Application.Quit() на объекте приложения, например. Следующие работы:

private static void DoExcel()
    {
        var application = new Application();
        var workbook = application.Workbooks.Add();
        var worksheet = workbook.Worksheets.Add();

        // Name that this will be saved as
        string name = workbook.FullName + ".xlsx";

        string fullPath = Path.Combine(Directory.GetCurrentDirectory(), name);
        // If a file of the same name exists, delete it so that we won't be prompted if
        // we want to overwrite it when we save
        if (File.Exists(fullPath))
            File.Delete(fullPath);

        // Save the workbook - otherwise we may be prompted as to whether we want to save when we go to quit
        workbook.Save();

        // Quit the application
        application.Quit();

        // Release the references
        Marshal.ReleaseComObject(worksheet);
        Marshal.ReleaseComObject(workbook);
        Marshal.ReleaseComObject(application);

        // Release the .NET reference and run the garbage collector now to make sure the application is closed immediately
        worksheet = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

Несколько других полезных вещей для запоминания: я не использовал его здесь, но есть http://marshal.finalreleasecomobject/, который очень полезен в этих случаях. Кроме того, опять же я не использовал это в моем примере кода, но Marshal.ReleaseComObject Метод возвращает текущий счетчик, поэтому вы всегда можете выполнить сброс в цикле, если хотите убедиться, что счетчик достиг нуля:

while (Marshal.ReleaseComObject(comObject) > 0) { }

Вы также можете использовать это в целях отладки - например,

int count = Marshal.ReleaseComObject(comObject);
Trace.TraceInformation("Current COM object reference count: " + count.ToString());
Другие вопросы по тегам