Delegates, Actions and Memory Allocations

It doesn't matter whether you explicit use new SomeDelegate or omit it, whether you use a lambda, the delegate keyword, or pass in a method group, or any possible solution you haven't shown. In every single case a delegate object will be created. The compiler can often infer that it should be there, so it doesn't force you to type it out; but the creation of that delegate is still happening no matter what. (Well, technically you could pass in null and not allocate an object, but then you can't ever do any work, so I think it's safe to ignore that case.)

The only real difference in memory allocations between each of the options is that in the given anonymous method blocks you are closing over a variable (workfinished). In order to create that closure the runtime will generate it's own type to store the state of the closure, create an instance of that type, and use that for the delegate, so all of the solutions using an anonymous method are creating one new object. (Granted, it's small, so it's not going to be particularly expensive in most situations.)


If you use a lambda expression which doesn't capture anything, the compiler will generate a static field to cache it in. So use that, you can change the Action to an Action<YourClass> and call it with this. So:

class YourClass
{
    private bool workFinished;

    public void DoWork()
    {
        MyMethod(instance => instance.Callback1Work(),
                 instance => instance.workFinished = false);
    }

    private void MyMethod(Action<YourClass> callback1,
                          Action<YourClass> callback2)
    {
        // Do whatever you want here...
        callback1(this);
        // And here...
        callback2(this);
    }

    private void Callback1Work()
    {
       // ...
    }
}

That will only create delegate instances the first time DoWork is called on any instance. The delegates will then be cached for all future calls on all instances.

Admittedly this is all an implementation detail. You could always make it clearer:

class YourClass
{
    private static readonly Action<YourClass> Callback1 = x => x.Callback1Work();
    private static readonly Action<YourClass> Callback2 = x => x.workFinished = false;

    private bool workFinished;

    public void DoWork()
    {
        MyMethod(Callback1, Callback2);
    }

    ... code as before ...
}

It's worth actually profiling and benchmarking the code before you go to any of these lengths though.

Another alternative would be to stick to Action, but create instance variables for the delegates - so as long as you called DoWork multiple times on the same instance, you'd be okay:

class YourClass
{
    private readonly Action foo;
    private readonly Action bar;

    private bool workFinished;

    public YourClass()
    {
        foo = Callback1Work;
        bar = () => workFinished = false;
    }

    public void DoWork()
    {
        MyMethod(foo, bar);
    }

    public void MyMethod(Action callback1, Action callback2)
    {
        ...
    }

    private void Callback1Work()
    {
        ...
    }
}

Tags:

C#

Delegates