2012-02-02 83 views
0

通常我需要最小化運行頻率非常高的代碼中的對象分配。
當然,我可以使用普通的技術,如對象池,但有時我只想要本地包含的東西。
要嘗試和實現這一目標,我想出瞭如下:避免重複分配沒有變量/成員的操作對象

public static class Reusable<T> where T : new() 
{ 
    private static T _Internal; 
    private static Action<T> _ResetAction; 

    static Reusable() 
    { 
     _Internal = Activator.CreateInstance<T>(); 
    } 

    public static void SetResetAction(Action<T> resetAction) 
    { 
     _ResetAction = resetAction; 
    } 

    public static T Get() 
    { 
#if DEBUG 
     if (_ResetAction == null) 
     { 
      throw new InvalidOperationException("You must set the reset action first"); 
     } 
#endif 

     _ResetAction(_Internal); 

     return _Internal; 
    } 
} 

目前,用法是:

// In initialisation function somewhere 
Reuseable<List<int>>.SetResetAction((l) => l.Clear()); 

.... 

// In loop 
var list = Reuseable<List<int>>.Get(); 
// Do stuff with list 

我想什麼來改善,是一個事實,即整個東西不包含在一個地方(.SetResetAction與它實際使用的地方是分開的)。

我想獲得的代碼類似下面:

// In loop 

var list = Reuseable<List<int>>.Get((l) => l.Clear()); 
// Do stuff with list 

這樣做的問題是,我得到一個對象分配(它創建了一個Action<T>)每一個循環。

是否有可能獲得使用後我沒有任何對象分配?

很明顯,我可以創建一個ReuseableList<T>這將有一個內置的Action,但我想允許其他情況下,行動可能會有所不同。

回答

4

您是否當然會在每次迭代時創建一個新的Action<T>?我懷疑它實際上沒有,因爲它沒有捕獲任何變量。我懷疑,如果你看看由C#編譯器生成的IL,它會緩存委託。

當然,這是實現特定的...

編輯:(我剛要離開之前,我有時間寫更多...)

正如埃裏克在評論中指出,這是依靠這個不是一個好主意。這是不能保證的,甚至當你不改變編譯器時,也很容易意外中斷它。

即使這個設計看起來令人擔憂(線程安全?),但如果你必須做到這一點,我可能把它從一個靜態類變成一個「正常」類,它需要復位方法(也可能是實例)在一個構造函數中。這是一種更靈活,可讀和可測試的IMO方法。

+0

我假設,我會仔細檢查。 – 2012-02-02 16:31:05

+0

你很對,它確實緩存了委託。 – 2012-02-02 16:42:55

+1

@GeorgeDuckett:小心不要依賴於此;小的改變可以改變緩存的生成。例如,如果lambda在本地關閉,如果它關閉「this」,如果外部方法是通用的,等等,委託生成的工作方式會有所不同。 – 2012-02-02 17:12:55