2010-02-23 26 views
2

我正在使用一個巨大的二叉樹,其結構的節點可能會或可能不會使用非託管資源。其中一些資源可能會佔用大量內存,但其中只有少數會一次被使用。樹的初始狀態可以被看作「休眠」。IDisposable對象意味着只創建一次嗎?

無論何時訪問節點,該特定節點及其子節點都將「醒來」並懶惰地獲取其分配的資源。同樣,訪問樹中的另一個分支會使當前活動的分支進入休眠狀態,導致其資源被釋放。這意味着任何給定的節點都可以在任何給定的時間被喚醒並一次又一次地休眠。

我目前正在利用IDisposable接口來實現此目的。這非常有用,因爲有很多情況下我需要創建將在本地使用的小型分支機構,並且「使用」關鍵字非常方便,確保不會意外打開任何資源。

我確定在沒有真正處置的物體上實施IDisposable,但有些處於睡眠狀態?

在此先感謝。

編輯:謝謝所有的聰明的答案。我喜歡處理資源訪問的想法,而不是資源本身。現在我正在爲負責清理的功能尋找一個更好的名字。 (比發行()或睡眠()?再次感謝。其他任何想法

+0

在此主題深入討論:http://stackoverflow.com/questions/2101524/is-it-abusive-to-use-idisposable-and-using-as-a-means-for-getting-scoped- behav – 2010-02-23 11:58:27

+0

@nobugz - 我不認爲這是完全相同的事情 - 儘管那個線程肯定是相關的 – philsquared 2010-02-23 12:16:56

回答

4

@Jon Skeetanswered the問題非常好,但讓我湊錢與評論,我覺得應該是自己的一個答案。

這是很常見的使用using代碼塊暫時獲得一些資源,或進入某種形式的作用域的代碼,你想從一個乾淨的退出。我一直這樣做,特別是在我的業務邏輯控制器中,我有一個系統推遲更改事件,直到執行代碼塊,避免多次副作用,或者在我爲他們做好準備之前,等

爲了使代碼看起來更明顯的使用它的程序員,你應該看看使用一個臨時值,你use而不是有資源的對象,並從一個方法名返回它告訴程序員它正在做什麼,即。暫時獲取一些資源。

讓我來舉個例子。

取而代之的是:

using (node) { ... } 

你這樣做:

using (node.ResourceScope()) { ... } 

因此,你實際上並不處置的任何一次以上,因爲ResourceScope將返回處置的新值,並且底層節點將保持原樣。

下面是一個例子實現(未經證實,從內存中輸入):

public class Node 
{ 
    private Resource _Resource; 

    public void AcquireResource() 
    { 
     if (_Resource == null) 
      _Resource = InternalAcquireResource(); 
    } 

    public void ReleaseResource() 
    { 
     if (_Resource != null) 
     { 
      InternalReleaseResource(); 
      _Resource = null; 
     } 
    } 

    public ResourceScopeValue ResourceScope() 
    { 
     if (_Resource == null) 
      return new ResourceScopeValue(this); 
     else 
      return new ResourceScopeValue(null); 
    } 

    public struct ResourceScopeValue : IDisposable 
    { 
     private Node _Node; 

     internal ResourceScopeValue(Node node) 
     { 
      _Node = node; 
      if (node != null) 
       node.AcquireResource(); 
     } 

     public void Dispose() 
     { 
      Node node = _Node; 
      _Node = null; 
      if (node != null) 
       node.ReleaseResource(); 
     } 
    } 
} 

這可以讓你做到這一點:

Node node = ... 
using (node.ResourceScope())  // first call, acquire resource 
{ 
    CallSomeMethod(node); 
}        // and release it here 

... 
private void CallSomeMethod(Node node) 
{ 
    using (node.ResourceScope()) // due to the code, resources will not be 2x acquired 
    { 
    }       // nor released here 
} 

,我返回一個結構,而不是事實IDisposable意味着你不會得到拳擊開銷,相反公開的.Dispose方法只會在using -block退出時被調用。

+0

+1非常感謝您的回答。這正是我所期待的。 – Trap 2010-02-23 14:08:46

2

我會說「不」。IDisposable有一個特定的目的,而「沉睡」不是吧。

5

這不完全從IDisposable.Dispose文檔,其中包括本(重點煤礦)明確:

執行與釋放,或重置非託管資源相關的應用定義的任務

也是這樣:

如果對象的Dispose方法是 調用一次以上,該對象必須 忽略第一個之後的所有呼叫。 如果其Dispose方法多次調用 ,則該對象不得拋出異常 。其他 實例方法比Dispose可以拋出 ObjectDisposedException當資源 已被處置。

後者表明它確實不應用於「復位」的操作,這是我想你了。 (我不知道你的「置於睡眠狀態」術語確實有助於在這裏;呢,我就在說你真的在所有子節點配置的所有主動獲取的資源)

當然,這只是按照慣例 - 你可以讓你的代碼做你喜歡的任何事情。不過,我認爲大多數開發人員會覺得有點奇怪。

我可以看到你正在嘗試做什麼,但我不確定最好的做法......

+0

「我是否正確地說你真的在所有子節點中處理所有主動獲取的資源?是的,喬恩,這正是我的意思。 – Trap 2010-02-23 12:32:37

+0

這是「擺脫沉重的負荷,但保持」邏輯上「​​完好未來用」 – Trap 2010-02-23 12:38:50

1

當然,你不應該釋放資源,如果你沒有得到他們,所以在這種情況下,您的Dispose方法不會做任何事情。

也許,你應該使用內用IDisposable的複合對象和分配/配置資源這一屬性/字段。所以你會醒來(爲資源分配新的對象),並讓你的節點處於活動狀態,進入休眠狀態(處置資源)。

在這種情況下,你的鋼需要自IDisposable派生節點,因爲當你有屬性/字段與IDisposable接口,容器應實現IDisposable了。

1

不,這似乎並不像一個適當的使用了IDisposable的。

快速思考你可以做什麼;實現另一個IDisposable對象,該對象可以包含已加載的數據,並從對象的方法調用中返回該數據;例如:

using(var wokenUpData = dataContainer.WakeUp()) 
{ 
    // access the data using wokenUpData 
    ... 
} 
+0

+1與菲爾一樣​​,我喜歡這種方法,謝謝:) – Trap 2010-02-23 14:06:59

1

聽起來像你只是需要添加額外的level of indirection

這裏正在迷茫的對象壽命。一方面你有一個長壽的對象(node),它並不總是使用其他資源。另一方面,你有一些節點可能在「醒來」時使用的其他資源,並且在返回睡眠狀態時(由於選擇了另一個節點)將放棄(如果我對你有好處)。

所以,它聽起來就像你有兩個壽命的概念,而這些可以通過引入另一個目的是更直接地管理資源進行建模。因此,將你的「懶惰獲得的資源」放到新的資源管理對象中,而資源管理對象本身也熱切地獲取資源 - 並將它們分配到dispose()中。然後,您的節點可以根據需要(在喚醒時)創建資源管理對象,並在完成時將它們處理掉(重新進入休眠狀態),並且壽命不會混淆。

+0

+1這是非常有益的。事實上,我已經在使用這種'間接指向'(我通常在其中添加'訪問'或'訪問者'這個詞),但這次我沒有看到樹木的森林。謝謝:) – Trap 2010-02-23 14:05:50