What do you think the following code will do?
- Compile time error
- Run time error
- Work fine
static void Main(string[] args) { int x = 10; int y = 5; Swap(ref x, ref y); } static void Swap(ref int x, ref int y) { int temp = x; x = y; y = temp; Func<int> closure = () => x; }
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++ :
int x = 5; 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:
class Capture { public int x; public int Lambda() { return this.x; } } static void Swap(ref int x, ref int y) { Capture capture = new Capture(); capture.x = x; int temp = capture.x; capture.x = y; y = temp; Func<int> closure = () => capture.x; }
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.