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

Releasing COM Object in Constructor Parameter

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

谁能帮助我,如果我正在有效地做,并告诉我垃圾收集器何时收集参数对象?

I just got to know I should release all the COM Objects, but I am searching for a proper way to release the someGoodSheet object in a proper way

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

如果您一直在编写一个独立的进程,它说通过 COM 启动 Excel 并摆弄一些 COM 对象,那么 是的,您需要确保COM 对象被适当地释放。

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

Marshal.ReleaseComObject(someGoodSheet);

因为你实际上是在对 COM "I'm finished with it" 说,但你不是,因为你仍然有一个通过 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;
    }
}

and tell me when parameter objects are collected by garbage collector?

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

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

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