Question

Ok so I know the difference (I think) between value types and reference types in C#. However, the code below does not behave the way I would expect knowing what I know about value types and reference types.

delegate void SomeHandler();

static Action GetSomeHandler()
 {
   int x = 1;

   SomeHandler a = delegate { Console.WriteLine(x); };

   x = 2;

   return a;
 }

static void Main(string[] args)
{
   SomeHandler a = GetSomeHandler();

   a();
}

I'm confused because a local variable "x" is declared and initialized to 1 inside my GetSomeHandler method. Then, a new delegate "a" of type SomeHandler is declared and assigned to an anonymous method that writes "x" to the console. "x" is then assigned to 2. Finally, "a" is invoked and the value of "x" is printed to the console.

I expected the output to be 1 because "x" is an int (a value type) and I would assume that when 2 was assigned to "x" it would not affect what I have used in my delegate because the value would be copied and not pointed to the same location in memory but the actual output is 2!! WHY!?

Was it helpful?

Solution

Ah, you have discovered the magic of closures!

You are correct in thinking that "x" is a value type and that it should not behave in this way; that is if you weren't declaring an anonymous function inside of your method. An anonymous method is a closure and is bound to its parenting method body and the local variables in it (In this case it is the local variable "x" and the parenting method GetSomeHandler).

The important distinction is that it is bound to variables, not to values. In other words, the value of "x" is not copied in when "a" is declared. Instead, a "reference" to "x" is used so that "a" will always use the most recent value of "x". In fact, this "reference" to "x" will be persisted even if "x" goes out of scope. When you compile your program the compiler then works some of its "compiler magic" and generates something similar to the following snippet of code:

delegate void SomeHandler();

// This is the helper class generated by the compiler that allows an anonymous function inside your method access to local variables even after the function or method has returned.
sealed class SomeHandlerClosure
{
   public int x;

   public void CompilerNamedMethod()
   {
     Console.WriteLine(x);
   }
}

static SomeHandler GetSomeHandler()
 {
   SomeHandlerClosure closure = new SomeHandlerClosure();
   closure.x = 1;

   SomeHandler a = new SomeHandler(closure.CompilerNamedMethod);

   closure.x = 2;

   return a;
 }

static void Main(string[] args)
 {
   SomeHandler a = GetSomeHandler();

   a();
 }

The "GetSomeHandler" method is really where the magic happens:

1.At the beginning of method, an instance of the "SomeClosure" class is created. (Note that I chose to use the names "SomeHandlerClosure" and "CompilerNamedMethod" for clarity. In reality, the compiler generates names to prevent name collision.)

2.All references to the local variable "x" in the "GetSomeHandler" method have been replaced with references to the "x" field on the "SomeHandlerClosure" instance.

3.The delegate "a" is now assigned to a new delegate instance for "CompilerNamedMethod" on the "SomeHandlerClosure" instance.

Clear as mud??

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top