There are several scenarios where we need to use value types as reference types:
Passing a value type to a method that takes a reference type, requires .NET boxing of the value type. The boxed value is copied into an opaque reference type and can only be accessed through un-boxing. Boxing/Unboxing in C# is done implicitly, but corresponds to special instructions in MSIL.
One frequently needs to modify a value type. As you may recall from Lesson2, value types are stored on the stack. So to modify a value type, we need modify the value stored in an address on the stack.
Here is a simple program that unsuccessfully attempts to modify an integer.
using System;
//does not change value of k
class Demo
{
public class Test
{
public void change (int k)
{
k=k+2;
}
}
public static void Main()
{
int i=3;
Test hi=new Test();
Console.WriteLine("Before {0} ", i);
hi.change(i);
Console.WriteLine("After {0} ", i);
}
}
If you compile and execute this program, you will find that the value of the integer have not been changed by the method change. The reason is quite simple: method change takes a value of i, makes a copy of it, adds 2 to the copy and returns control to the main. Value of i does not change.When change returns, its local copy of variable i disappears ( goes out of scope). When Console.WriteLine("After {0} ",i); is called, it uses i which was never changed. A simple fix is to modify method change so that it returns a value:
using System;
// Circumvent the problem of changing value of i.
class Demo
{
public class Test{
public int change (int k)
{
return k+2;
}
}
public static void Main()
{
int i=3;
Test hi=new Test();
Console.WriteLine("Before {0} ",i);
Console.WriteLine("After {0} ", hi.change(i));
}
}
The code above works fines but it does not change the value of i. To change i we need to pass it by reference. When passing by reference compiler changes i instead of changing a local copy. To do this we need to add keyword ref indicating that change takes a reference as an argument.
using System;
class Demo
{
public class Test{
public void change(ref int k)
{
k=k+2;
}
}
public static void Main()
{
int i=3;
Test hi=new Test();
Console.WriteLine("Before {0} ", i);
hi.change(ref i);
Console.WriteLine("After {0} ", i);
}
}
The output of this program is:
Before 3
After 5