Safely disposing Excel interop objects in C#?

后端 未结 2 867
Happy的楠姐
Happy的楠姐 2020-12-06 01:19

i am working on a winforms c# visual studio 2008 application. the app talks to excel files and i am using Microsoft.Office.Interop.Excel; to do this.

i

2条回答
  •  青春惊慌失措
    2020-12-06 01:57

    First I will present a modified releaseObject, and then I will provide a pattern to use it.

    using Marshal = System.Runtime.InteropServices.Marshal;
    private void releaseObject(ref object obj) // note ref!
    {
        // Do not catch an exception from this.
        // You may want to remove these guards depending on
        // what you think the semantics should be.
        if (obj != null && Marshal.IsComObject(obj)) {
            Marshal.ReleaseComObject(obj);
        }
        // Since passed "by ref" this assingment will be useful
        // (It was not useful in the original, and neither was the
        //  GC.Collect.)
        obj = null;
    }
    

    Now, a pattern to use:

    private void button1_Click(object sender, EventArgs e)
    {
        // Declare. Assign a value to avoid a compiler error.
        Excel.Application xlApp = null;
        Excel.Workbook xlWorkBook = null;
        Excel.Worksheet xlWorkSheet = null;
    
        try {
            // Initialize
            xlApp = new Excel.ApplicationClass();
            xlWorkBook = xlApp.Workbooks.Open(myBigFile, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", true, false, 0, true, 1, 0);
            // If the cast fails this like could "leak" a COM RCW
            // Since this "should never happen" I wouldn't worry about it.
            xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
            ...
        } finally {
            // Release all COM RCWs.
            // The "releaseObject" will just "do nothing" if null is passed,
            // so no need to check to find out which need to be released.
            // The "finally" is run in all cases, even if there was an exception
            // in the "try". 
            // Note: passing "by ref" so afterwords "xlWorkSheet" will
            // evaluate to null. See "releaseObject".
            releaseObject(ref xlWorkSheet);
            releaseObject(ref xlWorkBook);
            // The Quit is done in the finally because we always
            // want to quit. It is no different than releasing RCWs.
            if (xlApp != null) {
                xlApp.Quit();
            }
            releaseObject(ref xlApp);    
        }
    }
    

    This simple approach can be extended/nested over most situations. I use a custom wrapper class that implements IDisposable to make this task easier.

提交回复
热议问题