I encountered a behavior recently that I don't understand. I have a local function that captures variables/parameters from the enclosing method. In this case it seems to me that every time I call the enclosing method, a new "instance" of the local function will be created. This behavior is easy to see in the code below.
Can you explain to me why a local function behaves like this?
Neither VS or Resharper gives me any warning for doing this, but this is easy to miss and can cause difficult to find bugs.
public class LocalFunctionTest
{
public static void Main(string[] args)
{
var localFunctionTest = new LocalFunctionTest();
localFunctionTest.UnsubscribeSubscribe(1);
localFunctionTest.UnsubscribeSubscribe(10);
localFunctionTest.UnsubscribeSubscribe(100);
Console.WriteLine(localFunctionTest.EventWithoutClosure?.GetInvocationList().Length ?? 0); //1
Console.WriteLine(localFunctionTest.EventWithClosure?.GetInvocationList().Length ?? 0); //3
}
private void UnsubscribeSubscribe(int someParam)
{
void EventHandlerWithoutClosure(object sender, EventArgs args)
{
}
//Local function that captures a variable/parameter
void EventHandlerWithClosure(object sender, EventArgs args)
{
someParam++;
}
//Using local functions as event handlers
EventWithoutClosure -= EventHandlerWithoutClosure;
EventWithoutClosure += EventHandlerWithoutClosure;
EventWithClosure -= EventHandlerWithClosure;
EventWithClosure += EventHandlerWithClosure;
}
private event EventHandler EventWithoutClosure;
private event EventHandler EventWithClosure;
}
Some alternatives to the code above would be:
If you create a local variable inside the local function and assign the parameter to it, is still behaves like a closure.
If you create a field and assign the parameter to it in the enclosing method, and access the field in the local function, it won't behave like a closure.