簡體   English   中英

*每個* Excel互操作對象是否需要使用Marshal.ReleaseComObject釋放?

[英]Does *every* Excel interop object need to be released using Marshal.ReleaseComObject?

編輯

另請參閱如何正確清理Excel互操作對象? 我最近遇到了這個問題,它提供了很多關於如何正確處理COM對象的問題的見解。 絕對檢查超出第一個(標記的)答案,因為其他答案超出了簡單的“不使用兩個點”和“為每個com對象使用ReleaseComObject ”的建議。

我首先重新審視了這個問題,因為我意識到盡管注冊和處理所有COM對象非常徹底,但我的Excel實例仍然沒有得到妥善處理。 事實證明,有些方法可以創建完全不明顯的COM對象(即,即使您從不使用兩個點,也可以錯過COM對象)。 此外,即使您是徹底的,如果您的項目增長超過一定的大小,錯過COM對象的機會接近100%。 當發生這種情況時,很難找到你錯過的那個。 上面鏈接的問題的答案提供了一些其他技術,以確保Excel實例肯定關閉。 同時,我對我的ComObjectManager (下面)做了一個小的(但很重要的)更新,以反映我從上面鏈接的問題中學到的東西。

原始問題

我看過幾個例子,其中Marshal.ReleaseComObject()與Excel Interop對象(即名稱空間Microsoft.Office.Interop.Excel中的對象)一起使用,但我已經看到它用於不同程度。

我想知道我是否可以逃避這樣的事情:

var application = new ApplicationClass();
try
{
    // do work with application, workbooks, worksheets, cells, etc.
}
finally
{
    Marashal.ReleaseComObject(application)
}

或者,如果我需要釋放創建的每個對象,如此方法:

public void CreateExcelWorkbookWithSingleSheet()
{
    var application = new ApplicationClass();
    var workbook = application.Workbooks.Add(_missing);
    var worksheets = workbook.Worksheets;
    for (var worksheetIndex = 1; worksheetIndex < worksheets.Count; worksheetIndex++)
    {
        var worksheet = (WorksheetClass)worksheets[worksheetIndex];
        worksheet.Delete();
        Marshal.ReleaseComObject(worksheet);
    }
    workbook.SaveAs(
        WorkbookPath, _missing, _missing, _missing, _missing, _missing,
        XlSaveAsAccessMode.xlExclusive, _missing, _missing, _missing, _missing, _missing);
    workbook.Close(true, _missing, _missing);
    application.Quit();
    Marshal.ReleaseComObject(worksheets);
    Marshal.ReleaseComObject(workbook);
    Marshal.ReleaseComObject(application);
}

是什么促使我問這個問題的是,作為我的LINQ奉獻者,我真的想做這樣的事情:

var worksheetNames = worksheets.Cast<Worksheet>().Select(ws => ws.Name);

...但我擔心如果我不釋放每個工作表( ws )對象,我最終會遇到內存泄漏或重影過程。

任何有關這方面的見解將不勝感激。

更新

基於到目前為止的答案,聽起來我真的需要釋放我創建的每個com對象。 我借此機會構建了一個ComObjectManager類,以便更輕松地解決這個問題。 每次實例化一個新的com對象時都必須記住使用Get()方法,但如果這樣做,它將為您處理其他所有事情。 如果您發現任何問題,請告訴我(如果可以,請編輯並發表評論)。 這是代碼:

public class ComObjectManager : IDisposable
{
    private Stack<object> _comObjects = new Stack<object>();

    public TComObject Get<TComObject>(Func<TComObject> getter)
    {
        var comObject = getter();
        _comObjects.Push(comObject);
        return comObject;
    }

    public void Dispose()
    {
        // these two lines of code will dispose of any unreferenced COM objects
        GC.Collect();
        GC.WaitForPendingFinalizers();

        while (_comObjects.Count > 0)
            Marshal.ReleaseComObject(_comObjects.Pop());
    }
}

這是一個用法示例:

public void CreateExcelWorkbookWithSingleSheet()
{
    using (var com = new ComObjectManager())
    {
        var application = com.Get<ApplicationClass>(() => new ApplicationClass());
        var workbook = com.Get<Workbook>(() => application.Workbooks.Add(_missing));
        var worksheets = com.Get<Sheets>(() => workbook.Worksheets);
        for (var worksheetIndex = 1; worksheetIndex < worksheets.Count; worksheetIndex++)
        {
            var worksheet = com.Get<WorksheetClass>(() => (WorksheetClass)worksheets[worksheetIndex]);
            worksheet.Delete();
        }
        workbook.SaveAs(
            WorkbookPath, _missing, _missing, _missing, _missing, _missing,
            XlSaveAsAccessMode.xlExclusive, _missing, _missing, _missing, _missing, _missing);
        workbook.Close(true, _missing, _missing);
        application.Quit();
    }
}

我相信你必須在每個COM對象上調用ReleaseComObject。 由於它們不是垃圾收集的,因此父子層次結構並不真正進入等式:即使釋放父對象,它也不會減少任何子對象的引用計數。

您應該在代碼中使用的每個COM對象上調用Marshal.ReleaseComObject,而不僅僅是主應用程序對象。

不需要。您不必釋放單個COM對象。 請參閱以下答案: 使用IDisposable清理Excel Interop對象

總結答案:除非程序崩潰,否則垃圾收集器會在感覺到它時處理它們。 你需要注意的是:

  1. 在DEBUG模式下運行您的應用程序可能會延遲/阻止COM對象的清理。
  2. 停止調試器(從visual studio中)將阻止清理COM對象。 好像你崩潰了應用程序。
  3. 如果正確關閉調試的應用程序,您將看到所有COM對象都已釋放。 此外,在發布模式下運行您的應用程序並正確關閉它也將釋放所有COM對象。

現在,如果要在方法調用結束后立即釋放所有COM對象,則可以簡單地調用GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers();

但是你需要在這個OUTSIDE中調用創建COM對象的方法。 同樣,如果您正在調試應用程序,它可能無法按預期工作,但它將在發布模式下工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM