Often I need to minimise object allocations within code that runs very frequently.
Of course I can use normal techniques like object pooling, but sometimes I just want something that's contained locally.
To try and achieve this, I came up with the below:

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;
    }
}

Currently, the usage would be:

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

....

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

What I'd like to improve, is the fact that the whole thing is not contained in one place (the .SetResetAction is separate to where it's actually used).

I'd like to get the code to something like below:

// In loop

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

The problem with this is that i get an object allocation (it creates an Action<T>) every loop.

Is it possible to get the usage I'm after without any object allocations?

Obviously I could create a ReuseableList<T> which would have a built-in Action but I want to allow for other cases where the action could vary.

有帮助吗?

解决方案

Are you sure that creates a new Action<T> on each iteration? I suspect it actually doesn't, given that it doesn't capture any variables. I suspect if you look at the IL generated by the C# compiler, it will cache the delegate.

Of course, that's implementation-specific...

EDIT: (I was just leaving before I had time to write any more...)

As Eric points out in the comment, it's not a great idea to rely on this. It's not guaranteed, and it's easy to accidentally break it even when you don't change compiler.

Even the design of this looks worrying (thread safety?) but if you must do it, I'd probably turn it from a static class into a "normal" class which takes the reset method (and possibly the instance) in a constructor. That's a more flexible, readable and testable approach IMO.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top