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.
