【问题标题】:How does one release/dispose/destroy captured variables in anonymous methods?如何在匿名方法中释放/处置/销毁捕获的变量?
【发布时间】:2010-10-29 10:25:52
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 你知道当你一直在不停地做某事并最终突破它时的感觉吗?我在那里。感谢大家的帮助(包括来自单独帖子的 Marc Gravell)。我最终不得不保留一个 COM 对象列表和附加到它们的事件的匿名方法,然后在关闭之前取消注册委托。这使得事情在不抛出异常的情况下工作。

标签: c# com dispose anonymous-methods


【解决方案1】:

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

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

【讨论】:

  • 我在上面添加了更多信息。您是否认为保留引用对象的 List 并在完成后处理它们这样的事情是否合适?
【解决方案2】:

根据您的描述不太可能知道这一点,但也许您有一个 COM 对象,它持有对 C# 对象的引用,因为这些对象上的方法被登记为暴露在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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

    • 我在问题中添加了更多信息。任何帮助都会很棒。
    猜你喜欢
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-09
    • 2011-07-06
    • 1970-01-01
    相关资源
    最近更新 更多