Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从C#应用程序中正确清理Excel互操作对象?_C#_Excel_Office Interop - Fatal编程技术网

如何从C#应用程序中正确清理Excel互操作对象?

如何从C#应用程序中正确清理Excel互操作对象?,c#,excel,office-interop,C#,Excel,Office Interop,这个问题已经被问过很多次了,例如: 但Hans Passent对以下问题的回答让我相信这些问题已经过时和/或根本不正确: 所以,我的问题是: 如何清理Excel互操作对象,以便及时释放所有托管和非托管Excel资源(即当内存压力触发垃圾收集时) 在释放模式下 在调试模式下(如果我们关心的话) 在释放模式下: 仅仅让所有托管Excel互操作对象超出范围就足够了吗 我也需要调用excelApp.Quit()吗 非托管堆上的内存压力会触发垃圾回收吗?i、 e.我是否也需要打电话: GC

这个问题已经被问过很多次了,例如:

但Hans Passent对以下问题的回答让我相信这些问题已经过时和/或根本不正确:

所以,我的问题是: 如何清理Excel互操作对象,以便及时释放所有托管和非托管Excel资源(即当内存压力触发垃圾收集时)

  • 在释放模式下
  • 在调试模式下(如果我们关心的话)
在释放模式下:

仅仅让所有托管Excel互操作对象超出范围就足够了吗

我也需要调用excelApp.Quit()吗

非托管堆上的内存压力会触发垃圾回收吗?i、 e.我是否也需要打电话:

GC.Collect();
GC.WaitForPendingFinalizers();
确保我的托管应用不会耗尽内存? 我是否需要调用:System.Runtime.InteropServices.Marshal.FinalEleaseComObject(managedExcelObject)

除非您已经阅读并理解了Hans Passent的答案,否则请不要回答此问题。

随着我对C#Excel互操作的使用变得越来越复杂,在关闭应用程序后,我开始在Task Manager中运行“Microsoft Office Excel(32位)”对象的无头副本。我没有发现voodoo Marshal.ReleaseComObject()和GC.Collect()的组合可以完全消除它们。我最终删除了所有的巫毒密码,听从了汉斯·帕森特的建议。当应用程序关闭时,我可以使用以下模式在大多数情况下终止它们:

using System;
using System.IO;
using excel = Microsoft.Office.Interop.Excel;

namespace ExcelInterop {
    static class Program {
        // Create only one instance of excel.Application(). More instances create more Excel objects in Task Manager.
        static excel.Application ExcelApp { get; set; } = new excel.Application();

        [STAThread]
        static int Main() {
            try {
                ExcelRunner excelRunner = new ExcelRunner(ExcelApp)
                // do your Excel interop activities in your excelRunner class here
                // excelRunner MUST be out-of-scope when the finally clause executes
                excelRunner = null;  // not really necessary but kills the only reference to excelRunner 
            } catch (Exception e) {
                // A catch block is required to ensure that the finally block excutes after an unhandled exception
                // see: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally
                Console.WriteLine($"ExcelRunner terminated with unhandled Exception: '{e.Message}'");
                return -1;
            } finally {
                // this must not execute until all objects derived from 'ExcelApp' are out of scope
                if (ExcelApp != null) {
                    ExcelApp.Quit();
                    ExcelApp = null;
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
            }
            Console.WriteLine("ExcelRunner terminated normally");
            return 0;
        }
    }
}
在我的ExcelRunner课程中,我将数百个csv文件读入excel工作簿,并创建数十个带有表格和图表的.xlsx文件。我只创建了Microsoft.Office.Interop.Excel.Application()的一个实例,并反复使用它。更多实例意味着任务管理器中运行的更多需要清理的“Microsoft Office Excel”对象

请注意,必须执行finally子句,以除去无头Excel对象。上面的模式处理大多数应用程序关闭情况(包括大多数由未处理的异常导致的中止-但请参阅)。当您从VS调试器(Shift-F5或工具栏上的红色“停止调试”方框)中止应用程序时,会出现一个值得注意的异常。如果从调试器中止应用程序,则finally子句不会执行,Excel对象将保持运行状态。这是不幸的,但我找不到解决办法

我使用Excel 2007 interop和Excel 2016 interop在Visual Studio 2019和.NET Framework 4.7.2中对此进行了测试。

随着我对C#Excel interop的使用变得越来越复杂,在关闭应用程序后,我开始在Task Manager中运行“Microsoft Office Excel(32位)”对象的无头副本。我没有发现voodoo Marshal.ReleaseComObject()和GC.Collect()的组合可以完全消除它们。我最终删除了所有的巫毒密码,听从了汉斯·帕森特的建议。当应用程序关闭时,我可以使用以下模式在大多数情况下终止它们:

using System;
using System.IO;
using excel = Microsoft.Office.Interop.Excel;

namespace ExcelInterop {
    static class Program {
        // Create only one instance of excel.Application(). More instances create more Excel objects in Task Manager.
        static excel.Application ExcelApp { get; set; } = new excel.Application();

        [STAThread]
        static int Main() {
            try {
                ExcelRunner excelRunner = new ExcelRunner(ExcelApp)
                // do your Excel interop activities in your excelRunner class here
                // excelRunner MUST be out-of-scope when the finally clause executes
                excelRunner = null;  // not really necessary but kills the only reference to excelRunner 
            } catch (Exception e) {
                // A catch block is required to ensure that the finally block excutes after an unhandled exception
                // see: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally
                Console.WriteLine($"ExcelRunner terminated with unhandled Exception: '{e.Message}'");
                return -1;
            } finally {
                // this must not execute until all objects derived from 'ExcelApp' are out of scope
                if (ExcelApp != null) {
                    ExcelApp.Quit();
                    ExcelApp = null;
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
            }
            Console.WriteLine("ExcelRunner terminated normally");
            return 0;
        }
    }
}
在我的ExcelRunner课程中,我将数百个csv文件读入excel工作簿,并创建数十个带有表格和图表的.xlsx文件。我只创建了Microsoft.Office.Interop.Excel.Application()的一个实例,并反复使用它。更多实例意味着任务管理器中运行的更多需要清理的“Microsoft Office Excel”对象

请注意,必须执行finally子句,以除去无头Excel对象。上面的模式处理大多数应用程序关闭情况(包括大多数由未处理的异常导致的中止-但请参阅)。当您从VS调试器(Shift-F5或工具栏上的红色“停止调试”方框)中止应用程序时,会出现一个值得注意的异常。如果从调试器中止应用程序,则finally子句不会执行,Excel对象将保持运行状态。这是不幸的,但我找不到解决办法


我使用Excel 2007 interop和Excel 2016 interop在Visual Studio 2019和.NET Framework 4.7.2中对此进行了测试。

您会发现,所有使用过COM的人都理解这些答案,并且可以告诉您相同的答案。在大多数情况下,解决方案是尽可能不使用Office互操作。使用像Epplus这样的库来创建真正的
xlsx
文件。我同意。如果不需要,请不要使用互操作。使用类似的方法。你是否真的编写了你的程序,并证明了这里突出显示的项目是一个问题?在同一条船上,互操作的东西总是让人头痛不已<如果您只是想将工作表加载到内存中,那么code>ExcelDataReader是另一个值得一看的工具。@Robert Harvey我最初计划用Java编写我的应用程序。这篇文章:让我相信ApachePOI或OpenXML并没有很好地支持图表。因此,我选择了C#和Excel互操作系统,因为我相信它将是完整且易于使用的——事实确实如此。我的应用程序是一次性的,可以为我捕获的csv数据生成一堆(150多个)图表。如果它完成了,我真的不在乎它是否泄漏。这个问题实际上是为了扩大我对这个问题的理解。你会发现,每个曾经与COM合作过的人都理解这些答案,并且可以告诉你同样的答案。在大多数情况下,解决方案是尽可能不使用Office互操作。使用像Epplus这样的库来创建真正的
xlsx
文件。我同意。如果不需要,请不要使用互操作。使用类似的方法。你是否真的编写了你的程序,并证明了这里突出显示的项目是一个问题?在同一条船上,互操作的东西总是让人头痛不已<如果您只是想将工作表加载到内存中,那么代码>ExcelDataReader是另一个值得一看的工具。@Robert Harvey我本来打算这样做的