2009-10-08 25 views
7

如果你有一個刷子和筆,如:如何處理我們沒有參考的一次性物體?

Brush b = new SolidBrush(color); 
Pen p = new Pen(b); 

,並處理它們像這樣:

b.Dispose(); 
p.Dispose(); 

你將如何處置它,如果它是:

Pen p = CreatePenFromColor(color)這將創建刷和筆爲你?我不能在這個方法裏面放置畫筆,對吧?

這是一種不用於一次性物品的方法嗎?

編輯:我的意思是,你如何處置刷?

+0

o.O我不知道那個刷子和筆實現了IDisposable ... – 2009-10-08 18:09:17

+0

哈哈,它當然會。 – 2009-10-08 18:11:51

+0

但是這個Brush究竟在哪裏引用?如果你只是返回一個Pen作爲方法結果,爲什麼(以及在哪裏)創建它? – Groo 2009-10-08 18:12:47

回答

9

這是CreatePenFromColor方法處理Brush實例的工作。它一目瞭然並不明顯,但如果您深入研究Pen類的實現,您會發現它不能保持傳入的Brush實例。相反,它只是用它來計算一些值。因此,Brush實例沒有理由超出對CreatePenFromColor的調用,並且該方法應該處理該實例。

+0

謝謝Jared,我不知道。 – 2009-10-08 18:12:51

+0

這不一定是真的。 Pen構造函數將畫筆的句柄傳遞給'GdipCreatePen2'。我不知道'GdipCreatePen2'是否需要刷子保持活動狀態(該功能幾乎沒有記錄),但我猜測它確實存在。請記住,畫筆可以是帶有圖像的「TextureBrush」,並且您不希望筆在內存中創建圖像的單獨副本,以便您可以放置​​畫筆。 – SLaks 2009-10-08 18:25:24

+1

@Slaks,GdipCreatePen2 AFAIK不需要它活着。我通過非常有限的文檔挖掘,只需要安裝筆,而不是維護它。 – JaredPar 2009-10-08 18:32:31

6

你完成後仍然需要處理它。

例如,你可以這樣調用它:

using (Pen p = CreatePenFromColor(color)) 
{ 
    // do something 
} 

如果一個方法返回一個IDisposable的對象,這是你的職責,處置它。

[編輯]現在我得到了問題 - 你正在使用鋼筆(畫筆b)的構造函數。

a。在這種情況下,似乎筆不需要刷機實例構造後,所以你的方法看起來是這樣的:

public Pen CreatePenFromColor(Color c) 
{ 
    using (Brush b = new SolidBrush(c)) 
    { return new Pen(b); } 
} 

灣爲什麼不簡單地使用Pen(Color color)

public Pen CreatePenFromColor(Color c) 
{ 
    return new Pen(c); 
} 

c。 (關於評論)如果筆在內部持有對刷子的引用,那麼在完成筆之前,您將無法處理它。在這種情況下,我會去的一類會爲我做的工作:

public class PenHelper : IDisposable 
{ 
    private readonly Brush _brush; 
    public PenHelper(Color color) 
    { 
     _brush = new SolidBrush(color); 
    } 

    public Pen CreatePen() 
    { 
     return new Pen(_brush); 
    } 

    public void Dispose() 
    { 
     _brush.Dispose(); 
    } 
} 

,然後用它是這樣的:

using (PenHelper penHelper = new PenHelper(Color.Black)) 
{ 
    using (Pen pen = penHelper.CreatePen()) 
    { 
      // do stuff 
    } 
} 

免責聲明:IDisposable接口是根據準則沒有實現,但而僅用於演示。此外,整個示例僅用於顯示如何在需要時封裝引用。當然,你應該選擇Pen(彩色)。

+0

+1「爲什麼人們創造筆刷來創造筆?!?」 – 2009-10-08 18:29:52

+0

謝謝。在你的例子中,刷子b會在Pen返回時被處置,對嗎?如果Pen在內部提到刷B,那麼它會舉一個例子嗎?就是想。 – 2009-10-08 18:32:36

+0

感謝您的擴展示例。 – 2009-10-08 18:43:42

0

當一種方法取消了一個IDisposable實例時,它同時移交了終生管理職責。

現在是調用者在使用後處理對象的責任。如果該對象包含其他IDisposable對象,那麼按照約定,我們必須期望容器在我們處置它時正確處理它的子項 - 否則這將意味着容器中存在一個錯誤。

在您的具體示例中,您應該期望Pen在處置它時處置其內部的Brush實例。

+0

顏色也是一次性的嗎? – 2009-10-08 18:09:05

+1

不,顏色是一個結構。 – Groo 2009-10-08 18:10:04

+1

@Joan Venge:'Typo' - 我在糾正您的評論的同時...... – 2009-10-08 18:10:44

2

您的問題沒有一般解決方案。

在您的具體示例中,這不是問題,因爲Pen具有直接使用Color的構造函數。有些類會自己處理它們的構造函數參數(特別是Stream相關的類)。檢查反射器中的每個類。

如果您要返回的類從Component繼承,則可以爲其Disposed事件添加處理程序。

如果你要返回的類不是密封的,你可以創建一個繼承的版本來處理你創建它的對象。

最後,如果你真的想,你可以創建一個包裝類,它包含你要返回的對象並處理構造函數參數。但是,這會很混亂,我不會推薦它。

+0

謝謝,我不知道Pen可以直接使用Color。這很有趣,因爲我看到很多代碼分別創建筆刷和筆,然後使用筆進行繪畫。 – 2009-10-08 18:16:15

+0

然後你應該接受這個答案。 – SLaks 2009-10-08 18:22:02

+0

是的,它的確如此。它只是沒有一個乾淨的通用解決方案。 – SLaks 2009-10-08 18:30:59

1

我的一個與許多與圖形相關的類peeves是沒有一致的模式來處理這些問題。真正需要的是實現部分引用計數的手段。不在COM風格中,傳遞引用需要不斷地引用計數,但是通過給定IDisposable圖形對象,可以請求另一個共享相同底層資源的實例。資源本身將被封裝在帶有引用計數器的共享對象中。創建另一個引用實例會增加計數器;在引用實例上調用Dispose會減少它。這將避免引用計數的95%的開銷,同時保留99%的收益。