Reputation: 139
Here is the test class:
public class TestClass
{
private readonly Action _action;
public TestClass()
{
_action += () => { Console.WriteLine("1"); };
Subscribe(_action);
_action?.Invoke();
}
private static void Subscribe(Action action)
{
action += () => { Console.WriteLine("2"); };
}
}
When running the "2" is not printed since the lambda subscribed to the action is not invoked.
It appears to me that when passing an Action as an argument, it is sort of passed by value (in C++ terms) so the call to the += operator happens on another instance of the Action.
How do I pass an Action as parameter such that I can later subscribe to it using the += operator. Or maybe using Actions is not valid for this purpose?
Upvotes: 1
Views: 69
Reputation: 13676
The reason is that when the compiler sees +=
operator with delegate it uses Delegate.Combine
method in order to concatenate the invocation lists of delegates and this returns new delegate.
You can check it if you call Console.WriteLine(action.GetHashCode());
before and after +=
operator
So you're actually trying to change the variable from outer scope by assigning a new value to a variable in inner scope (method-scoped variable).
Explanation:
When we pass Action
delegate as parameter it creates a method-scoped variable and puts a reference to this delegate into it. Later when we call +=
operator it returns a new reference and assigns it to the same method-scoped variable. At this point it is pointing to another object whilst the original _action
variable is still pointing to initial object.
If you want to assign new value for a variable created outside of method's scope and to change its pointer you could pass it by reference using ref
keyword. This will indicate to compiler that an argument is passed by reference, not by value:
private static void Subscribe(ref Action action)
{
action += () => { Console.WriteLine("2"); };
}
Upvotes: 2