2009-05-27 53 views
1

我正在使用匿名方法來處理COM對象中的事件。一旦程序終止,看來我在匿名方法中使用的資源沒有被「正確關閉」,因爲我收到了我正在觀看的每個資源的第一次機會異常(InvalidComObjectException)。我想這不是什麼大不了的事情,但它並不覺得「正確」。如何釋放/處理/銷燬匿名方法中的捕獲變量?

我無法想象一種方法來訪問匿名方法範圍之外的那些捕獲的變量(無論如何你都不應該這樣做)。如何在退出申請前關閉/處理資源?

編輯:經過短暫的重讀,可能不清楚我在這裏做什麼。我正在編寫一個使用COM對象的託管應用程序。

更多編輯:我正在使用ArcGIS Engine來操作GIS數據。在這種特殊情況下,我在ILayerEvents_Event中使用VisibilityChanged事件來監視GIS圖層何時可見或不可見。該事件只傳遞一個布爾(可見或不可見)而不是圖層名稱,因此需要爲每個圖層創建一個方法來創建其可見性狀態更改。由於我正在處理動態圖層,因此我需要一種方式來動態執行此操作,因此需要使用匿名方法。

在anonymoua方法中,我有一個ILayer變量,它從外部循環(在ILayer上下文中)中獲取ILayerEvents_Event,以便我知道我正在使用哪個圖層。在這一點上,我卡住了。這些功能可以正常工作,一切都很好,直到我退出應用程序,這些20多個引用掛在那裏,沒有地方可去,而是發生異常。

我不知道用戶何時會最後一次隱藏/顯示一個圖層,因此無法在最後一步將它清空。我想我可以保持原樣(或者,也許有比匿名方法更好的方法),因爲它似乎不會傷害任何東西。我只是覺得我錯過了一些東西。

+0

你知道,當你一直在做一些不停的事情並且最終突破它時,你會感覺到嗎?我在那裏。感謝大家的幫助(包括來自單獨發佈的Marc Gravell)。我最終不得不保留一個COM對象列表以及附加到它們事件的匿名方法,然後在關閉之前取消註冊這些委託。這使得事情沒有拋出異常。 – 2009-05-28 16:03:36

回答

1

從你如何描述它是不太可能的,但也許你有一個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對象發生的唯一事情就是將釋放它們。如果這是造成問題的原因,那很可能是因爲他們已經處於無效狀態。

因此,我建議您在製作一組匿名方法閉包時,它保存對COM對象的引用,還應該將這些COM對象添加到單獨的列表中。這將允許您在丟棄整個系統時,然後撥打Marshal.ReleaseComObject

1

如果你真的想,你需要掛鉤到應用程序退出事件。不過,我認爲能夠做得比這更好。

你使用匿名方法是什麼?你能解決它最後一次使用的時間,然後處理COM對象嗎?你可以使匿名方法獲取COM對象處置它們,都在同一個塊內?

正如你所看到的,魔鬼在細節:)

+0

我在問題中添加了更多信息。任何幫助都會很棒。 – 2009-05-27 22:54:06

2

嘗試使用不安全的方式在C#中,在堆上創建的東西,並在完成後刪除它。另一個想法是將資源的引用存儲在匿名方法之外的變量中,並在程序終止時正確關閉它們。然後再次,您可能需要的只是調用Dispose()。

多一點信息會有幫助。什麼時候拋出異常?你是什​​麼意思的資源和「正確關閉」。

+0

我已經在上面添加了更多信息。你認爲像保持被引用對象的List <>然後在完成時處理它們會有所幫助嗎? – 2009-05-27 22:55:38