2012-02-02 55 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