2014-09-19 69 views
0

背景:C#:如何處置作爲它自己的事件的結果一個包含的對象?

我有一個得到了住在我的應用程序的UI線程主要對象。這個長期存在的父/容器對象包含一個作爲內部多線程的私有成員的子對象。

基於從孩子/包含對象發佈的某些事件,我希望父對象簡單地Dispose()孩子並重新創建它。

包含的對象擁有一些非託管資源以及一些大的託管內存緩衝區。

創建頂級對象,這是否對事件處理程序,但這意味着要被設置在物體會在方法調用即將取代它的調用堆棧。 (!)

這是因爲事件處理程序委託將由它自己的線程上的某個子對象的狀態處理函數調用。

這似乎...錯了。沒有?

特別是,孩子的FireAnEvent()方法將在處理委託調用後恢復執行,只是現在執行將在已經「處置」的對象的上下文中恢復。

直覺上,我看不到這導致好東西。

問:

有一個既定的C#模式銷燬包含的對象,因爲它本身的事件的結果?

或者,是否有GC魔法讓某個簡單的事件處理程序足夠好?

或者,我錯過了一些關鍵的理解?

+0

是短期居住的兒童對象,而不是長期居住的父母?而通過父母和孩子你是指類和子類,還是容器和包含? – Assaf 2014-09-19 00:43:23

+0

可能是您需要創建一些線程控制邏輯,一旦您的孩子檢測到它需要終止,它將終止線程。或者讓你的孩子進入獨立的過程。然後,終止這個孩子將意味着該過程中的所有線程被破壞,只要您將其標記爲「背景」即可。 http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground%28v=vs.110%29.aspx – 2014-09-19 00:44:49

+0

這是主觀的。如果完全有C#模式,那麼請考慮一下,沒有一個Microsoft組件具有「如果此事件和該事件未被觸發,您只能調用Dispose()」手冊頁。這是一個不明智的事情,你通常不能確定程序員是否考慮過這種可能性。當然,這不是你的問題,你可以很容易地測試它,修復很容易。如果你討厭這個想法,那就考慮另一種方法,你總是可以使用BeginInvoke()來稍後執行Dispose調用。一個優秀的調度員循環:) – 2014-09-19 01:11:38

回答

1

調用IDisposable.Dispose()並不表示.NET框架的任何特殊功能。你唯一需要做的就是刪除你想要刪除的對象的任何引用。一旦完成並且對象不在調用堆棧中,它將成爲垃圾收集的候選對象。

請注意,您的對象不一定會立即垃圾收集,甚至下次GC運行;這僅僅是一種假定的可能性。

IDisposable的唯一目的是提供一個標準的方法來請求對象清理自己並釋放資源。只要你願意,你可以持有對「處置」對象的引用,這將阻止GC收集對象。 IDisposable.Dispose()只是另一種方法;從技術上講,你可以讓它做任何你想要的。

這個問題有一個非常漂亮的詳細的回答可以幫助你瞭解IDisposable多一點:Proper use of the IDisposable interface提到

+0

謝謝你的回答,我已經更新了這個問題,稍作澄清。我知道'Dispose()'是爲了釋放非clr資源,並且GC刪除可能暫時不會發生。問題是我看到的對象在調用Dispose()之後並不期望被使用。然而,在這裏,我們將恢復執行一個已經釋放底層資源的對象。 – ddl877 2014-09-19 16:59:46

+0

然後你需要保證在你觸發事件時調用Dispose(),或者你需要一個解決方案,在調用Dispose()之前將對象從調用堆棧中移出。後者可以通過多種方式完成。由於這是一個單獨的子對象,所以你可以在父對象上設置一個標誌,然後使用Hans Passant對BeginInvoke()的建議處理它,排隊一個任務,在一個事件上有一個線程塊併發信號給事件,可能還有其他許多人。只要確保您避免造成競爭狀況。 – Taudris 2014-09-20 00:43:59

0

,一個IDisposable對象是什麼魔力。它只是讓你用using簡寫,這僅僅是一個簡寫:

try { // code in the using block } 
catch{} 
finally{ 
    disposableObject.Dispose() 
} 

你有沒有考慮引入第三類型的對象混進去?被遏制的物體意識到它們的容器是不正確的。大致這將是您的工作流程:

  1. 包含對象決定它應該重新啓動。包含對象的
  2. 釋放資源。
  3. 包含對象寫入第三個對象(不包含對象)上的隊列。
  4. 當您覺得您應該創建新的包含對象並重新實例化對象時,包含對象將訪問隊列。或者,向隊列中添加事件以便將容器清空。

第三個對象可能看起來毫無意義,但如果您決定重構,它會讓您的生活變得輕鬆許多。

0

爲通知目的訂閱事件的對象應該隨時準備接收通知,即使它們已被處置後也是如此。通知的目的是告訴一個對象做任何事情來應對已發生的事情。如果一個對象在響應通知時不能做任何有用的事情,它就不應該做任何事情。

此外,Dispose的目的不是要「銷燬」一個對象,也不是它所包含的資源,而是將它從任何可能對外部對象承擔的義務中釋放出來,並允許它釋放任何外部實體從他們可能對其承擔的任何義務。在許多情況下,一旦釋放承諾的外部實體的服務,一個對象就毫無用處,因此已經處理的對象不能被期望有用;如果在Disposed之後調用的方法因爲必要的外部實體已被釋放而不能滿足其職責,那麼它應該丟棄ObjectDisposedException而不是以其他方式失敗

把這些意見放在一起,雖然處置對象上的許多方法應該拋出ObjectDisposedException,但通知事件處理程序方法不應該,因爲它們指示對象「做你需要做的事情來履行你的義務,已經發生了」。如果一個物體被處置,它沒有義務。因此,處置並不妨礙對象滿足事件處理程序合同;相反,它允許對象通過靜默(「成功」)無所事事來滿足合同。

相關問題