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

本文关键字:COM 对象 参数 释放 构造函数 | 更新日期: 2023-09-27 18:22:07

我正在开发一个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;
    }
}

如果我能有效地做到这一点,有人能帮助我吗?并告诉我垃圾收集器何时收集参数对象?

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

我刚刚知道我应该释放所有的COM对象,但我正在寻找一种合适的方式来以合适的方式释放someGoodSheet对象

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

如果你一直在写一个独立的过程,比如通过COM启动Excel,并篡改了一些COM对象,那么,你需要确保COM对象得到适当的释放。

不要在你的构造函数中使用这个:

Marshal.ReleaseComObject(someGoodSheet);

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


对复制到字段的参数调用Marshal.ReleaseComObject有点像在调用Dispose()之后使用Font——两者都会导致访问已擦除对象的不良情况。(在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参数将不会被收集,因为现在您在ExtraOrdinaryClass中的tDesignSheet中有了对它的额外引用。您可能需要将tDesignSheet设置为null,然后等待GC下次运行(无论何时)

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

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