如何声明Microsoft.Office.Interop.Excel.Worksheet以便用C#关闭它?

如何声明Microsoft.Office.Interop.Excel.Worksheet以便用C#关闭它?,c#,office-interop,com-interop,excel-interop,C#,Office Interop,Com Interop,Excel Interop,我很难确保我的COM对象正在关闭,因此我不会让EXCEL.EXE进程在后台运行。我了解到声明的双点和链接是不好的,因为这可能会使COM对象悬而未决 有人知道如何修复这行代码,以便我可以正确地关闭和释放工作表COM对象吗 worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Sheets[strName]; 编辑:在执行完此行后,我尝试使用app.Quit()关闭打开的Excel对象,但这不起作用。但是,如果我在这一行之前调

我很难确保我的COM对象正在关闭,因此我不会让EXCEL.EXE进程在后台运行。我了解到声明的双点和链接是不好的,因为这可能会使COM对象悬而未决

有人知道如何修复这行代码,以便我可以正确地关闭和释放工作表COM对象吗

worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Sheets[strName];

编辑:在执行完此行后,我尝试使用app.Quit()关闭打开的Excel对象,但这不起作用。但是,如果我在这一行之前调用app.Quit(),它会工作。

首先,为了让EXCEL.EXE进程退出,您不必显式释放所有使用的COM对象。当您获取对COM对象的另一个引用时,.NET运行时为您隐式创建的运行时可调用包装(RCW)由GC收集,这将释放底层COM对象

您所要做的就是调用Quit方法,释放RCWs引用并让GC收集它们

//This runs the EXCEL.EXE process.
Microsoft.Office.Interop.Excel.Application app = 
    new Microsoft.Office.Interop.Excel.Application();
//This locks the excel file either for reading or writing 
//depending on parameters.
Microsoft.Office.Interop.Excel.Workbook book = app.Workbooks.Open(...);

...

//Explicitly closing the book is a good thing. EXCEL.EXE is alive 
//but the excel file gets released.
book.Close();

//This lets the EXCEL.EXE quit after you release all your references to RCWs
//and let GC collect them and thus release the underlying COM objects. 
//EXCEL.EXE does not close immediately after this though.
app.Quit();
app = null;
其次,如果保留所谓的双点代码行,则不会产生任何内存泄漏。垃圾收集器将收集RCW,并在某个时候(即找到正确的时候)释放COM对象

最后,如果您希望显式地释放RCW和相应的COM对象以尽可能降低内存压力,那么您可以在释放对它们的引用之后显式地调用GC来收集RCW,甚至在GC收集RCW之前显式地释放底层COM对象。不过要小心。最后一种方法让您对以下事实负责:此后,将不再使用剩余的RCW,否则将出现异常

using Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;

Application app = new Application();
Workbooks books = clsExcelApplication.Workbooks;
Workbook book = books.Open("...");
Sheets sheets = book.Sheets;
Worksheet sheet = sheets["..."];

...

//Trying to be as explicit as we can.
book.Сlose();

//Revese order. Using FinalReleaseComObject is even more dangerous. 
//You might release an object used inside excel
//code which might lead to some dreadful internal exceptions.
int remainingRefCount;
remainingRefCount = Marshal.ReleaseComObject(sheet);
remainingRefCount = Marshal.ReleaseComObject(sheets);
remainingRefCount = Marshal.ReleaseComObject(book);
remainingRefCount = Marshal.ReleaseComObject(books);
app.Quit();
remainingRefCount = Marshal.ReleaseComObject(app);
记住。如果手动释放COM引用,则EXCEL.EXE的生存期不依赖于RCW,您可以在需要时将其置为空

sheet = null;
sheets = null;
book = null;
books = null;
app = null;

在最明确的情况下,不要忘记检查Marshal.ReleaseComObject的返回。如果它不是零,则除了您刚刚发布的RCW之外,还有其他人持有对您的基础COM对象的COM引用。

首先,为了让EXCEL.EXE进程退出,您不必显式地发布您使用的所有COM对象。当您获取对COM对象的另一个引用时,.NET运行时为您隐式创建的运行时可调用包装(RCW)由GC收集,这将释放底层COM对象

您所要做的就是调用Quit方法,释放RCWs引用并让GC收集它们

//This runs the EXCEL.EXE process.
Microsoft.Office.Interop.Excel.Application app = 
    new Microsoft.Office.Interop.Excel.Application();
//This locks the excel file either for reading or writing 
//depending on parameters.
Microsoft.Office.Interop.Excel.Workbook book = app.Workbooks.Open(...);

...

//Explicitly closing the book is a good thing. EXCEL.EXE is alive 
//but the excel file gets released.
book.Close();

//This lets the EXCEL.EXE quit after you release all your references to RCWs
//and let GC collect them and thus release the underlying COM objects. 
//EXCEL.EXE does not close immediately after this though.
app.Quit();
app = null;
其次,如果保留所谓的双点代码行,则不会产生任何内存泄漏。垃圾收集器将收集RCW,并在某个时候(即找到正确的时候)释放COM对象

最后,如果您希望显式地释放RCW和相应的COM对象以尽可能降低内存压力,那么您可以在释放对它们的引用之后显式地调用GC来收集RCW,甚至在GC收集RCW之前显式地释放底层COM对象。不过要小心。最后一种方法让您对以下事实负责:此后,将不再使用剩余的RCW,否则将出现异常

using Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;

Application app = new Application();
Workbooks books = clsExcelApplication.Workbooks;
Workbook book = books.Open("...");
Sheets sheets = book.Sheets;
Worksheet sheet = sheets["..."];

...

//Trying to be as explicit as we can.
book.Сlose();

//Revese order. Using FinalReleaseComObject is even more dangerous. 
//You might release an object used inside excel
//code which might lead to some dreadful internal exceptions.
int remainingRefCount;
remainingRefCount = Marshal.ReleaseComObject(sheet);
remainingRefCount = Marshal.ReleaseComObject(sheets);
remainingRefCount = Marshal.ReleaseComObject(book);
remainingRefCount = Marshal.ReleaseComObject(books);
app.Quit();
remainingRefCount = Marshal.ReleaseComObject(app);
记住。如果手动释放COM引用,则EXCEL.EXE的生存期不依赖于RCW,您可以在需要时将其置为空

sheet = null;
sheets = null;
book = null;
books = null;
app = null;

在最明确的情况下,不要忘记检查Marshal.ReleaseComObject的返回。如果它不是零,则除了您刚刚发布的RCW之外,还有其他人持有对您的基础COM对象的COM引用。

我发现,只要您确保关闭所有处理的内容并发布excelapp。退出它就可以了-我确实在找到的一些预处理exporttoexcel代码中发现了一些问题,但最后还设置了excelapp=null,这确保了GC不会释放COM组件的任何东西都不会被挂起。您必须显式地这样做。@Enigmativity GC不会释放通过某些API获得的纯COM对象,但会释放通过运行时可调用包装器获得的COM对象。在使用excel的情况下,它确实可以释放它们。@BugFinder将excelapp设置为null不会有太大变化。这只会释放对与excel app COM对象对应的RCW的引用。它不会影响EXCEL.EXE进程的结束,也不会确保您不持有对其他RCW(COM对象)的其他引用,如工作簿或工作表。不,但我确实发现从长远来看,这会产生实际影响,我从未调查过原因,但如果我对该行进行注释,EXCEL.EXE将保持打开状态。有了空值,它们都会消失。可靠且及时。我发现只要你确保你关闭了你处理的所有东西并发布excelapp。退出它就行了-我确实在我找到的一些预处理exporttoexcel代码中发现了一些问题,但在最后设置excelapp=null时,这确保了没有任何东西挂起GC不会发布COM组件。您必须显式地这样做。@Enigmativity GC不会释放通过某些API获得的纯COM对象,但会释放通过运行时可调用包装器获得的COM对象。在使用excel的情况下,它确实可以释放它们。@BugFinder将excelapp设置为null不会有太大变化。这只会释放对与excel app COM对象对应的RCW的引用。它不会影响EXCEL.EXE进程的结束,也不会确保您不持有对其他RCW(COM对象)的其他引用,如工作簿或工作表。不,但我确实发现从长远来看,这会产生实际影响,我从未调查过原因,但如果我对该行进行注释,EXCEL.EXE将保持打开状态。有了空值,它们都会消失。可靠及时。