代码之家  ›  专栏  ›  技术社区  ›  Michael Todd

如何在匿名方法中释放/处置/销毁捕获的变量?

  •  1
  • Michael Todd  · 技术社区  · 17 年前

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

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

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

    ArcGIS Engine 操纵GIS数据。在这个特定的情况下,我使用ILayerEvents_event中的VisibilityChanged事件来监视GIS层何时可见或不可见。事件只传递一个bool(可见或不可见),而不传递层名称,因此需要为每个层创建一个方法来创建其可见性状态更改。由于我处理的是动态层,我需要一种动态的方法来实现这一点,因此需要匿名方法。

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

    3 回复  |  直到 17 年前
        1
  •  1
  •   Daniel Earwicker    17 年前

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

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

        2
  •  2
  •   Brent    17 年前

    从你的描述中不太可能知道这一点,但也许你有一个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对象添加到单独的列表中。这将允许您拨打电话 元帅。释放ComObject 当你抛弃整个系统时,它们就会消失。

        3
  •  1
  •   Jon Skeet    17 年前

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

    你使用匿名方法是为了什么?你能计算出它最后一次使用的时间,然后处理COM对象吗?你能让匿名方法获取COM对象吗 把它们都放在同一个街区内?

    正如你所看到的,魔鬼在细节中:)