1

我正在使用匿名方法来处理 COM 对象中的事件。一旦程序终止,我在匿名方法中使用的资源似乎没有被“正确关闭”,因为我看到的每个资源都会出现第一次机会异常 (InvalidComObjectException)。我想这没什么大不了的,但感觉并不“正确”。

我无法理解在匿名方法范围之外访问那些捕获的变量的方法(无论如何,你不应该这样做)。如何在退出应用程序之前关闭/处置资源?

编辑:经过简短的重新阅读后,我可能不清楚我在这里做什么。我正在编写一个使用 COM 对象的托管应用程序。

进一步编辑:我正在使用ArcGIS Engine来操作 GIS 数据。在这种特殊情况下,我使用 ILayerEvents_Event 中的 VisibilityChanged 事件来监视 GIS 图层何时可见或不可见。该事件仅传递一个布尔值(可见或不可见)而不是图层名称,因此需要为每个图层创建一个方法来创建其可见性状态更改。由于我正在处理动态层,因此我需要一种以某种方式动态执行此操作的方法,因此需要匿名方法。

在 anonymoua 方法中,我有一个 ILayer 变量,它从外部循环(在 ILayer 上下文中)获取 ILayerEvents_Event,以便我知道我正在使用哪个层。正是在这一点上,我被困住了。在我退出应用程序之前,该功能正常工作,一切都很好,让这 20 多个引用挂在那里,无处可去,只有一个例外。

我不知道用户何时会最后一次隐藏/显示图层,因此无法在最后一次将内容归零。我想我可以保持原样(或者,也许有比匿名方法更好的方法),因为它似乎没有伤害任何东西。我只是觉得我错过了一些东西。

4

3 回答 3

2

尝试在 C# 中使用不安全模式,在堆上创建内容并在完成后将其删除。另一个想法是将资源的引用存储在匿名方法之外的变量中,并在程序终止时正确关闭它们。再说一次,您可能需要的只是调用 Dispose()。

多一点信息会有所帮助。什么时候抛出异常?资源和“正确关闭”是什么意思。

于 2009-05-27T22:50:40.660 回答
1

如果您真的想要,您需要挂钩应用程序退出事件。但是,我认为做得比这更好。

你用匿名方法做什么?你能算出最后一次使用它的时间,然后处理COM对象吗?你可以让匿名方法获取 COM 对象在同一个块中处理它们吗?

如您所见,魔鬼在细节中:)

于 2009-05-27T22:43:36.867 回答
1

从您如何描述它不太可能知道这一点,但也许您有一个持有对 C# 对象的引用的 COM 对象,因为这些对象上的方法被登记为 COM 对象上公开的事件的事件处理程序,当 COM 对象不再使用时,它会被最终确定。假设 COM 对象是基于“公寓”的,这意味着消息将从终结器线程发送到创建 COM 对象的线程的 Windows 消息队列,请求在 COM 对象上调用 Release。此时,COM 对象可能会在实现任何登记事件处理程序的 C# 对象上调用 Release。当应用程序的最后一个托管代码完成运行时,这一切都可能发生,因此 CLR 正处于尝试卸载自身的过程中。可能在关闭期间,CLR 必须通过允许在对象的引用计数降至零之前收集对象或将其置于无效状态来应对任何可能的引用计数泄漏。所以这可能(纯粹的猜想)解释了你所看到的。

如果是这样,您需要在您自己选择的时间关闭 COM 对象。解决方案是在一个循环中调用Marshal.ReleaseComObject,直到它在 COM 对象上返回零,作为应用程序正常关闭的一部分。

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject(VS.71).aspx

更新,基于更新的问题:

好的,所以您有一些由匿名方法闭包引用的 COM 对象。这些 COM 对象唯一会发生的事情是 Release 将在它们上被调用。如果这引起了问题,很可能是由于它们已经处于无效状态。

因此,我建议当您创建一组包含对 COM 对象的引用的匿名方法闭包时,您还应该将这些 COM 对象添加到单独的列表中。这将允许您Marshal.ReleaseComObject在丢弃整个系统时调用它们。

于 2009-05-27T23:04:59.553 回答