Search code examples
c#delegates

How to add another action to an action in C#?


Why this code will print only "A" and "B", but not "C" ?

Action act = null;
act += () => MessageLog.Message("A");
act += () => MessageLog.Message("B");
Action<Action> add = a => a += () => MessageLog.Message("C");
add(act);
act.Invoke();

Solution

  • Delegates are immutable. The += operator creates a new delegate with an invocation list consisting of the invocation list from the left side, followed by the invocation list from the right hand side of the operator. It then stores a reference to that delegate in the variable on the left hand side. So

    act += () => MessageLog.Message("A");
    

    is equivalent to

    act = act + (Action) (() => MessageLog.Message("A"));
    

    which is in turn equivalent to:

    act = (Action) Delegate.Combine(act, (Action) (() => MessageLog.Message("A"));
    

    So, now we can come to your add delegate. This lambda expression:

    a => a += () => MessageLog.Message("C");
    

    ... modifies the parameter a to refer to the newly combined delegate... and then ignores it.

    Instead, you need to return the combined delegate (so change add to be a Func<Action, Action>) and then use the return value when you invoke add:

    Action act = null;
    act += () => MessageLog.Message("A");
    act += () => MessageLog.Message("B");
    Func<Action, Action> add = a => a + () => MessageLog.Message("C");
    act = add(act);
    act.Invoke();