What do you think the following code will do?

  1. Compile time error
  2. Run time error
  3. Work fine
   1: static void Main(string[] args)
   2: {
   3:     int x = 10;
   4:     int y = 5;
   5:     Swap(ref x, ref y);
   6: }
   7:  
   8:  
   9: static void Swap(ref int x, ref int y)
  10: {
  11:     int temp = x;
  12:     x = y;
  13:     y = temp;
  14:     Func<int> closure = () => x;
  15: }

 

If you said 1. Compile time error then you would be correct.  The resulting error message is:

Cannot use ref or out parameter 'x' inside an anonymous method, lambda expression, or query expression  

The reason for this is that although C# provides the ability to pass parameters by reference (as opposed to by value), it offers no way to assign to a variable by reference.

This ability exists in C++ :

   1: int x = 5;
   2: int & y = x;

Now y refers to the same variable location as x.

 

So, what does this all have to do with the original code?  As I described in my previous post Understanding Variable Capturing in C#, since we are using the variable x in a lambda expression (a.k.a. a closure) the C# compiler will rewrite the method so that it looks something like this:

   1: class Capture
   2: {
   3:     public int x;
   4:     public int Lambda()
   5:     {
   6:         return this.x;
   7:     }
   8: }
   9:  
  10: static void Swap(ref int x, ref int y)
  11: {
  12:     Capture capture = new Capture();
  13:     capture.x = x;
  14:     int temp = capture.x;
  15:     capture.x = y;
  16:     y = temp;
  17:     Func<int> closure = () => capture.x;
  18: }

 

Do you see the problem now?  On line 13 the ref parameter x  is being assigned to the member variable x of the Capture class.  But since you can't assign by reference this would change the semantics of the method.  The C# compiler is smart enough to know this, so it throws the error.  It won't generate code that has different meaning than what the user intended.