簡體   English   中英

Excel COM對象未釋放

[英]Excel COM object not being released

加載用戶的設置文件后,我試圖進行一次干凈的Excel中斷。 除了遇到與字典有關的問題外,我遇到了其他我無法解決的問題。 如果我注釋掉詞典填充括號中的一個(或兩個),設置文件將加載然后釋放,但是如果兩個都在運行,則excel應用程序將不會釋放。 我是否也通過從字典中獲取數據來將excel與字典聯系在一起?

我確信還有其他創建全局詞典的方法,但這是我目前唯一的知己,但是我願意學習是否有更好的方法。

“字典填充代碼”是i&j的for循環:

for (int i = 0; i < lastRow - 1; i++)
    {
        string key = settingsSheet.Range["B" + (i + 2)].Value; 
        string value = settingsSheet.Range["A" + (i + 2)].Value; 
        DictionaryLoad.DIC.Add(key, value);
    }

這是完整的代碼:

public Form1()
    {
        InitializeComponent();
        txtFileNamePreface.Enabled = false;
        string fileName = "F:\\Shared\\Projects\\State Assoc Clients\\Data Management\\Download Site\\KeyStats Download Statistics\\Naming Conventions.xls";
        LoadProductName(fileName);
    }

    public static class DictionaryLoad
    {
        public static IDictionary<string, string> DIC;
        public static IDictionary<string, string> DIC2;
        static DictionaryLoad()
        {
            DIC = new Dictionary<string, string>();
            DIC2 = new Dictionary<string, string>();
        }
    }

    private void LoadProductName(string fileName)
    {
        //starting up and defining the Excel references
        Excel.Application excelApp = new Excel.Application(); //excel open here
        Excel.Workbook settingsBook = null;
        Excel.Worksheet settingsSheet = null;
        excelApp.Visible = false;
        excelApp.DisplayAlerts = false;

        settingsBook = excelApp.Workbooks.Open(fileName);
        settingsSheet = settingsBook.Sheets["NamingConventions"]; 

        int lastRow = findFirstBlankRow(settingsSheet, "A1") - 1;
        fillComboBox(cbProductType, lastRow, settingsSheet, "A"); 
        fillComboBox(cbYear, lastRow, settingsSheet, "D");

        int lastRow2 = findFirstBlankRow(settingsSheet, "E1");
        fillComboBox(cbRule, lastRow2, settingsSheet, "E");

        for (int i = 0; i < lastRow - 1; i++)
        {
            string key = settingsSheet.Range["B" + (i + 2)].Value; 
            string value = settingsSheet.Range["A" + (i + 2)].Value; 
            DictionaryLoad.DIC.Add(key, value);
        }

        cbProductName.Items.Clear();
        foreach (KeyValuePair<string, string> entry in DictionaryLoad.DIC)
        {
            if (entry.Value == cbProductType.Text)
            { cbProductName.Items.Add(entry.Key); }
        }
        try { cbProductName.SelectedIndex = 0; }
        catch { }

        for (int j = 0; j < lastRow - 1; j++)
        {
            string key = settingsSheet.Range["B" + (j + 2)].Value; 
            string value = settingsSheet.Range["C" + (j + 2)].Value;
            DictionaryLoad.DIC2.Add(key, value);
        }

        cbRule.SelectedIndex = 0;
        cbYear.Text = DateTime.Now.Year.ToString();
        cbQuarter.SelectedIndex = 0;
        cbMonth.Text = DateTime.Now.ToString("MMMM");
        cbProductType.SelectedIndex = 0;
        string workBookName = excelApp.ActiveWorkbook.FullName;
        txtOutputFolder.Text = Path.GetDirectoryName(workBookName);

        settingsBook.Close();
        excelApp.Quit();
        appCleanup(excelApp);
        appCleanup(settingsBook);
        appCleanup(settingsSheet);
        garbageCleanup();
        Application.Exit();
    }
   public void appCleanup(object application1, object application2 = null, object application3 = null)
    {
        Marshal.ReleaseComObject(application1);
        application1 = null;
    }

    public void garbageCleanup()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
  1. 您無需在這種情況下調用Marshal.ReleaseComObject 運行時完全能夠跟蹤COM對象並在不再引用它們時釋放它們。 調用Marshal.ReleaseComObject是一個令人困惑的反模式,可悲的是,甚至某些Microsoft文檔也錯誤地提出了這種反模式。

    在您的情況下,這意味着應刪除appCleanup那些調用,盡管您可能仍必須設置application1 = null來清除引用-您的代碼不應使用此變量。

  2. 您應該兩次調用垃圾收集器例程-您可能遇到引用形成一個循環的情況,並且第一次GC調用將中斷該循環,但是COM對象可能僅在第二次調用時才能正確釋放。

  3. 最后,您必須在調試版本中謹慎使用此類代碼。 方法中的引用被人為保留,直到方法結束,以便它們仍可在調試器中訪問。 這意味着將無法通過在該方法內調用GC來清除本地excelApp變量。 為避免此問題,您可以遵循以下模式:

     public void LoadProductNameAndCleanup(string fileName) { LoadProductName(fileName); garbageCleanup(); garbageCleanup(); } 

我認為也許您應該使用string.Copy,因為否則您的字典將保留對鏈接到Excel對象的字符串對象的引用。 這將創建字符串對象的新實例:

for (int i = 0; i < lastRow - 1; i++)
{
    string key = string.Copy(settingsSheet.Range["B" + (i + 2)].Value); 
    string value = string.Copy(settingsSheet.Range["A" + (i + 2)].Value); 
    DictionaryLoad.DIC.Add(key, value);
}

暫無
暫無

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

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