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

时间:2009-05-27 22:39:00

标签: c# com dispose anonymous-methods

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

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

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

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

在anonymoua方法中,我有一个ILayer变量,它从外部循环(在ILayer上下文中)抓取ILayerEvents_Event,以便我知道我正在使用哪个层。就在这时我才被困住了。在我退出应用程序之前,这个功能很有效,而且一切都很宏,留下那些20多个引用,没有地方可以去除例外。

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

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:1)

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

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

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

根据更新的问题进行更新:

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

所以我建议当你创建一组包含COM对象引用的匿名方法闭包时,你也应该将这些COM对象添加到一个单独的列表中。这样您就可以在丢弃整个系统时调用Marshal.ReleaseComObject