To ref or not to ref
- by nmarun
So the question is what is the point of passing a reference type along with the ref keyword? I have an Employee class as below: 1: public class Employee
2: {
3: public string FirstName { get; set; }
4: public string LastName { get; set; }
5:
6: public override string ToString()
7: {
8: return string.Format("{0}-{1}", FirstName, LastName);
9: }
10: }
In my calling class, I say:
1: class Program
2: {
3: static void Main()
4: {
5: Employee employee = new Employee
6: {
7: FirstName = "John",
8: LastName = "Doe"
9: };
10: Console.WriteLine(employee);
11: CallSomeMethod(employee);
12: Console.WriteLine(employee);
13: }
14:
15: private static void CallSomeMethod(Employee employee)
16: {
17: employee.FirstName = "Smith";
18: employee.LastName = "Doe";
19: }
20: }
After having a look at the code, you’ll probably say,
Well, an instance of a class gets passed as a reference, so any changes to the instance inside the CallSomeMethod, actually modifies the original object. Hence the output will be ‘John-Doe’ on the first call and ‘Smith-Doe’ on the second.
And you’re right:
So the question is what’s the use of passing this Employee parameter as a ref?
1: class Program
2: {
3: static void Main()
4: {
5: Employee employee = new Employee
6: {
7: FirstName = "John",
8: LastName = "Doe"
9: };
10: Console.WriteLine(employee);
11: CallSomeMethod(ref employee);
12: Console.WriteLine(employee);
13: }
14:
15: private static void CallSomeMethod(ref Employee employee)
16: {
17: employee.FirstName = "Smith";
18: employee.LastName = "Doe";
19: }
20: }
The output is still the same:
Ok, so is there really a need to pass a reference type using the ref keyword? I’ll remove the ‘ref’ keyword and make one more change to the CallSomeMethod method.
1: class Program
2: {
3: static void Main()
4: {
5: Employee employee = new Employee
6: {
7: FirstName = "John",
8: LastName = "Doe"
9: };
10: Console.WriteLine(employee);
11: CallSomeMethod(employee);
12: Console.WriteLine(employee);
13: }
14:
15: private static void CallSomeMethod(Employee employee)
16: {
17: employee = new Employee
18: {
19: FirstName = "Smith",
20: LastName = "John"
21: };
22: }
23: }
In line 17 you’ll see I’ve ‘new’d up the incoming Employee parameter and then set its properties to new values. The output tells me that the original instance of the Employee class does not change.
Huh? But an instance of a class gets passed by reference, so why did the values not change on the original instance or how do I keep the two instances in-sync all the times?
Aah, now here’s the answer. In order to keep the objects in sync, you pass them using the ‘ref’ keyword.
1: class Program
2: {
3: static void Main()
4: {
5: Employee employee = new Employee
6: {
7: FirstName = "John",
8: LastName = "Doe"
9: };
10: Console.WriteLine(employee);
11: CallSomeMethod(ref employee);
12: Console.WriteLine(employee);
13: }
14:
15: private static void CallSomeMethod(ref Employee employee)
16: {
17: employee = new Employee
18: {
19: FirstName = "Smith",
20: LastName = "John"
21: };
22: }
23: }
Viola! Now, to prove it beyond doubt, I said, let me try with another reference type: string.
1: class Program
2: {
3: static void Main()
4: {
5: string name = "abc";
6: Console.WriteLine(name);
7: CallSomeMethod(ref name);
8: Console.WriteLine(name);
9: }
10:
11: private static void CallSomeMethod(ref string name)
12: {
13: name = "def";
14: }
15: }
The output was as expected, first ‘abc’ and then ‘def’ - proves the 'ref' keyword works here as well.
Now, what if I remove the ‘ref’ keyword? The output should still be the same as the above right, since string is a reference type?
1: class Program
2: {
3: static void Main()
4: {
5: string name = "abc";
6: Console.WriteLine(name);
7: CallSomeMethod(name);
8: Console.WriteLine(name);
9: }
10:
11: private static void CallSomeMethod(string name)
12: {
13: name = "def";
14: }
15: }
Wrong, the output shows ‘abc’ printed twice.
Wait a minute… now how could this be? This is because string is an immutable type. This means that any time you modify an instance of string, new memory address is allocated to the instance. The effect is similar to ‘new’ing up the Employee instance inside the CallSomeMethod in the absence of the ‘ref’ keyword.
Verdict: ref key came to the rescue and saved the planet… again!