在我的析构函数中释放Excel对象

Mur*_*rat 8 .net excel destructor release finalizer

我正在使用Microsoft.Interropt.Excel DLL编写Excel类.我完成了所有功能,但我的析构函数中有错误.我想将所有更改保存到我的文件中,并且我想要释放所有源代码.我希望所有这些都在我的析构函数中.但在我的析构函数中,Excel.ApplicationClass,Workbook和Worksheet对象由异常填充,其中包含消息"已与其基础RCW分离的COM对象无法使用".所以我不能保存任何东西,什么都不关闭因为ı无法访问工作簿或工作表对象.

我不能在Destructor中访问类私有成员吗?

Mik*_*lum 16

.NET与析构函数最接近的是.NET称为终结器.主要区别在于析构函数通常具有确定性终结(例如,当对象上的引用计数变为零时),而.NET终结器在不再引用对象后的未确定时间被调用.这由.NET垃圾收集器使用根跟踪过程处理,而不是使用简单的引用计数.

其中最好的文章之一是垃圾收集:Microsoft .NET Framework中的自动内存管理.有关终结器的更多信息,请参阅MSDN中的文章Finalize Methods and Destructors.

我不能在Destructor中访问类私有成员吗?

不,你不能安全地这样做.

在您的情况下发生的事情是,当您的对象不再被根直接或间接引用时,您的对象引用的COM对象(即您的私有字段引用的对象)也不会被根引用无论是.(由对象的字段引用不会使这些COM对象保持活动状态,因为您的对象不再被根引用或从根跟踪,因此,COM对象也不会从根跟踪.)所以您的对象和所有的COM对象引用它都愿意被垃圾收集在同一时间.一段时间后,垃圾收集器将清理你的对象并调用它的终结器,因为它也将与COM对象一起使用,每个对象实际上都是一个运行时可调用包装器(RCW).

麻烦的是,不仅是这些对象何时被垃圾收集不确定的时间,而且调用终结器的顺序也是不确定的.在这种情况下,运行时可调用包装器也有一个终结器,它自己调用Marshal.ReleaseComObject,其结果是减少围栏COM端的引用计数,以便释放此COM对象.但由于调用终结器的顺序是不确定的,因此很有可能对象引用的COM对象的终结器将在对象的终结器之前触发.所以终结器中的代码可以 有时工作,但是,大多数情况下,在终结器执行其代码之前,您的对象引用的一个或多个Runtime Callable Wrappers已经调用了终结器,并且底层COM对象将被释放.

简而言之,您应该避免使用终结器,并且永远不应该从终结器中访问引用类型,因为这些引用类型可能已经完成.

为了纠正你的情况,我会考虑两种不同的可能性:

  1. 在创建它们的相同方法中处置COM对象.我在这里这里有几个讨论.

  2. 通过使用IDisposable接口启用对象的确定性处理,而不是依赖于非确定性终结器.

有关如何实现IDisposable模式的文章,请参阅:

- 迈克