通常我需要在非常频繁运行的代码中最小化对象分配 当然我可以使用像对象池这样的常规技术,但有时我只想要一些本地包含的东西 为了实现这一目标,我想出了以下内容:
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>
的{{1}},但我想允许其他情况可能会有所不同。
答案 0 :(得分:4)
你确定在每次迭代时创建一个新的Action<T>
吗?我怀疑它实际上没有,因为它没有捕获任何变量。我怀疑如果你看一下C#编译器生成的IL,它会缓存委托。
当然,那是特定于实现的......
编辑:(在我有时间写作之前我刚刚离开......)正如埃里克在评论中指出的那样,依靠这一点并不是一个好主意。它不能保证,即使你不改变编译器也很容易意外破坏它。
即使这样的设计看起来令人担忧(线程安全?)但是如果你必须这样做,我可能会把它从静态类变成一个采用重置方法的“普通”类(可能是实例)在构造函数中。这是一种更灵活,可读和可测试的方法IMO。