Why is my INT variable being passed by reference?? C#

user3538345

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!?

Jason Roell

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??

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Why is my variable not properly being passed in React Native?

Are DateTimes passed by reference in C#? If not, why is my object updating as I change a variable?

Why does my operator + overload call my copy constructor despite being passed by reference?

Variable p passed by reference before being initialized

Why isn't the array being passed by reference?

Objects seemingly not being passed by reference in C++

Why are my meteor settings not being passed to the application?

Why is my array being passed with an incorrect size?

Why is Context not being passed to my HOC

Why is my input not being passed into the if statements?

Why is my search function not being passed?

Why is nothing being passed to my overloaded function?

Why a const variable cannot be passed by reference?

Why is my Variable Value Being Doubled Visual C#

Why doesn't the value of my variable change even though I passed by reference

Why is a bad pointer being passed into my native exported methods from C#?

Why don't I have to specify that the result of a fortran function is being passed by value to my C++ program?

Why are my props not being passed to my child component?

Why is only half my data being passed into my dictionary?

Why isn't my prop logging or being passed in React Native?

Why are my hidden input not being passed in the model class?

Why aren't my arguments being passed to the parameters?

Why aren't the values from my directive being passed into the function?

Flutter: Why is my function passed to `StatelessWidget` not is not being executed?

Flutter: Why is my custom function passed to a `StatelessWidget` object not being executed?

Why is a function being passed in?

List<int[]> passed by reference?

Why is my implicitly Copyable variable being moved?

Why are my variable values being deleted?