在构造函数参数中释放COM对象

时间:2015-11-17 04:38:14

标签: c# .net garbage-collection vsto com-object

我正在开发一个VSTO插件,现在我正在寻找优化它。在我的代码中,我做了一些事情

public class ExtraOrdinaryClass
{
    public ExtraOrdinaryClass(Excel.Worksheet someGoodSheet)
    {
        tSheetName            = someGoodSheet.Name;
        tDesignSheet          = someGoodSheet;
    }
}

我只是知道我应该释放所有COM对象,但我正在寻找一种正确的方法来以正确的方式释放someGoodSheet对象。我怀疑如果我做下面的事情是有效的

public class ExtraOrdinaryClass
{
    public ExtraOrdinaryClass(Excel.Worksheet someGoodSheet)
    {
        tSheetName            = someGoodSheet.Name;
        tDesignSheet          = someGoodSheet;
        Marshal.ReleaseComObject(someGoodSheet);
        someGoodSheet = null;
    }
}

如果我有效地执行此操作并且告诉我垃圾收集器何时收集参数对象,那么任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:0)

  

我只是知道我应该释放所有的COM对象,但我正在寻找一种正确的方式以正确的方式释放someGoodSheet对象

由于您正在编写VSTO加载项,因此无需担心释放COM对象。 VSTO加载项是由COM应用程序加载的进程内 COM库,在本例中为Excel。 Excel工作表表示的COM对象是由Excel创建的,因此它具有所有权。尝试手动释放(通过Marshal.ReleaseComObject)或在您仍然拥有托管引用时非常减少引用计数(如第二个示例中所示),可能会导致Excel和/或应用程序崩溃。

如果您正在编写一个独立的过程,即通过COM启动Excel并摆弄一些COM对象,然后,则需要确保COM对象被正确释放。

即。 在构造函数中使用它:

Marshal.ReleaseComObject(someGoodSheet);

因为你基本上是对COM"我已经完成了它"但你不是因为你仍然通过tDesignSheet引用了一个托管。 COM / Excel可能会选择从您下面删除工作表。下次访问tDesignSheet时,您可能会遇到异常。

在复制到字段的参数上调用Marshal.ReleaseComObject有点像在调用Font后使用Dispose() - 这两种情况都会导致被删除的对象出现意外情况访问。 (在COM的情况下,我假设引用计数达到0)

没有必要来调用它(因为你无论如何都引用了同一个对象):

someGoodSheet = null;

您的原始代码(如下所示)很好:

public class ExtraOrdinaryClass
{
    public ExtraOrdinaryClass(Excel.Worksheet someGoodSheet)
    {
        tSheetName            = someGoodSheet.Name;  // you arguably don't need this (just read tDesignSheet.Name)          
        tDesignSheet          = someGoodSheet;
    }
}
  

告诉我什么时候垃圾收集器收集参数对象?

我想说在这种情况下,不会收集.NET参数,因为现在您在tDesignSheet ExtraOrdinaryClass内有一个额外的引用。您需要将tDesignSheet设置为null并等待GC下次运行,无论何时都是。

即使收集了.NET对象,我怀疑.NET足够聪明,知道COM对象可能仍然被其他本机COM客户端使用,例如Excel本身。

因此,仅仅因为您的.NET现在处理的对象不再引用COM对象,您可能会发现COM对象仍然可以处于活动状态。例如工作表仍然是开放的。