COM对象excel互操作清理

时间:2012-03-24 13:08:57

标签: c# com excel-interop

让我们说我有一个组件正在使用Workbook对象,并且在该方法体的中间某处我调用了另一个类的某个方法。 例如:

public class MainComponent
{

    public void MyMainMethod()
    {
       OtherComponent otherComponent = new OtherComponent();
       Workbook document;
       // some work with workbook object

       // working with document and worksheet objects.
       otherComponent.MethodCall(document);

       // some work with workbook object and it's worksheets.

       foreach(Worksheet sheet in document.Workheets)
         // do something with sheet
    }
}

public class OtherComponent
{
  public void MethodCall(Workbook document)
  {
    string worksheetNames = "";
    foreach(Worksheet sheet in document.Worksheets)
      worksheetNames += sheet.Name;
    Console.WriteLine(worksheetNames);
  }
}

在那个otherComponent.MethodCall(文件);我正在使用文档,我正在迭代它的工作表。

编辑更具体的问题。我应该在文档和otherComponent.MethodCall(document)中的Worksheets上调用ReleaseCOMObject吗?

我从未真正对如何管理这种非托管代码有任何好的解释。 如果有人能向我解释,我真的很感激。

1 个答案:

答案 0 :(得分:4)

您必须在创建它们的范围内手动释放所有本地对象。通过自动化使用Office应用程序时,不要依赖垃圾收集器来清理这些对象 - 即使它正确,它可能需要一段时间才能启动,并且最终可能会有一些临时对象持有对其他对象的引用你认为已经消失了。

This is a somewhat related question如果您尝试在隐藏Excel的应用程序中运行Excel,则可能会向您提供更多详细信息。

与您明确相关的部分是:

  • try..catch块中使用Excel的每个函数包装起来,以捕获任何可能的异常。
  • 始终通过调用Marshal.ReleaseComObject()显式释放所有Excel对象,然后在不需要时将变量设置为null。始终在finally块中释放这些对象,以确保失败的Excel方法调用不会导致悬空的COM对象。
  • 发生错误时,请关闭您正在使用的Excel实例。您可能无法从与Excel相关的错误中恢复,并且保留实例的时间越长,使用资源的时间就越长。
  • 当您退出Excel时,请确保您针对递归调用保护该代码 - 如果您的异常处理程序在您的代码已经在关闭Excel的过程中尝试关闭Excel时,您将最终得到一个死Excel实例
  • 在调用GC.Collect()方法后立即调用GC.WaitForPendingFinalizers()Application.Quit(),以确保.NET Framework立即释放所有Excel COM对象。

修改这是在您向问题添加更多详细信息之后。

otherComponent中,您无需释放WorkbookDocument个对象。在您的第一个对象中创建这两个对象,这意味着第一个对象是所有者。由于它是拥有顶级Excel对象的第一个对象(假设您某处有Application个对象),因此您的第一个对象可以调用otherComponent,传递Workbook和{{1然后返回,清理它们。如果您从未在Document中使用任何这些对象,则应在MainComponent中创建与Excel相关的对象并在那里进行清理。

使用COM互操作,您应该将COM对象创建为靠近您需要它们的位置,并尽快明确释放它们。对于Office应用程序尤其如此。

我使这个类更容易使用COM对象:这个包装器是一次性的,所以你可以对你的COM对象使用otherComponent - 当using(...)范围结束时,包装器释放COM对象

using