.NET Reference and Value Types

Today's post sounds very basic, maybe you guess so, but I have seen so many developers around misuse these terms, so let's ask the classical question: "what is the difference between passing parameters to a method by value and by reference?", the answer that you may get from most developers is : if you pass a parameter by value the value of this parameter will not change after calling the function/method, though it gets changed inside the function implementation, the reason behind that whenever you pass a parameter by value the parameter's contents get copied into the method, and upon return of the method the calling code will be having the same value it had before calling the method, regardless of the inner implementation of the method, on the other hand whenever you pass the parameter by reference if the parameter gets changed inside the method implementation, and when the method returns the parameter's passed value will get affected depending on the method's implementation, so this is the answer you would get when you ask this question, but I have seen so many people just answer the question without being aware of the inner workings of ByVal and ByRef, so I decided to post this post to clear out the confusion by giving practical examples.

Value types are saved in an area in the memory called "Stack" where it's very efficient to update, read, delete the values quickly, on the other hand the reference types' references or "pointers" are saved in the "Stack", but the contents of these reference types are saved in the "Heap", basically all processing on the reference types are done on the pointers or references of the reference types not the values, and it's worth mentioning that Garbage Collector works on the Heap by removing, periodically, items that have no references, however GC works behind the scenes by removing these unusable data, but if you want to force GC to clean unusable memory you can call GC.Collect, let's examine this example to see all possible combinations by which you can manage reference and value types, also don't forget that the structure is a value type and the enumerator as well, but all objects are reference types.

Open your Visual Studio, and create a new C# Console application, give it any meaningful name such as ByValVsByRef, and then copy the following code into your Program.cs



1 using System;


2 using System.Collections.Generic;


3 using System.Text;


4 using System.Collections;


5


6 namespace ByValVsByRef


7 {


8 class Program


9 {


10 static void Main(string[] args)


11 {


12 /// start : Calling Value Type such as string by value and by reference


13 string greeting = "Hello From Main!";


14 Console.WriteLine("Value of string variable BEFORE calling byVal function is : {0}", greeting);


15 ValueTypeByVal(greeting);


16 Console.WriteLine("Value of string variable AFTER calling byVal function is : {0}", greeting);


17 Console.WriteLine("Value of string variable BEFORE calling byRef function is : {0}", greeting);


18 ValueTypeByRef(ref greeting);


19 Console.WriteLine("Value of string variable AFTER calling byRef function is : {0}", greeting);


20 /// end : Calling Value Type such as string by value and by reference


21


22 /// start : Calling Reference Type such as Hashtable by value and by reference


23


24 Hashtable ht = new Hashtable();


25 ht.Add("1", "1");


26 Console.WriteLine("Items' count of hashtable variable BEFORE calling byVal function is : {0}", ht.Count.ToString());


27 RefTypeByVal(ht);


28 Console.WriteLine("Items' count of hashtable variable AFTER calling byVal function is : {0}", ht.Count.ToString());


29 Console.WriteLine("Items' count of hashtable variable BEFORE calling byRef function is : {0}", ht.Count.ToString());


30 RefTypeByRef(ref ht);


31 Console.WriteLine("Items' count of hashtable variable AFTER calling byRef function is : {0}", ht.Count.ToString());


32 /// end : Calling Reference Type such as Hashtable by value and by reference


33 Console.ReadLine();


34 }


35


36 static void ValueTypeByVal(string s)


37 {


38 s = "Hello from inside the ValueTypeByVal method!";


39 }


40 static void ValueTypeByRef(ref string s)


41 {


42 s = "Hello from inside the ValueTypeByRef method!";


43 }


44


45 static void RefTypeByVal(Hashtable ht)


46 {


47 ht.Add("2", "2");


48 ht.Add("3", "3");


49 ht.Add("4", "4");


50 }


51


52 static void RefTypeByRef(ref Hashtable ht)


53 {


54 ht.Add("5", "5");


55 ht.Add("6", "6");


56 ht.Add("7", "7");


57 }


58 }


59 }


The output of the above code is as depicted in the following screen shot:


In the above code we set a string variable's value and then call two different methods in which we modify the contents of the variable, also for the reference type we declared a HashTable and added an initial item, then we passed the variable to two different methods the first takes the reference type by value and the second by reference, if you have a look at the code you will get to the following rule,

  • Passing a value type variable by value doesn't affect the variable's value.
  • Passing a value type variable by reference changes the variable's value.
  • Passing a reference type variable by value changes the variable, because the variable's or object's contents are not passed, but the object's pointer or memory location is getting passed to the method, and the method works on the pointer that ultimately changes the object's contents.
  • Passing a reference type variable by reference changes the variable, because in this case the pointer of the object's pointer is getting passed to the method, and in this case it yields the same behavior as in passing the reference type by value.
Very Important Note:
For the reference types if you are overwriting the object inside the method and the object reference is passed by value, then the calling code will not have the updated object data, in this case you have to pass by reference to get only the data that’s, to clarify this point add the following line at the beginning of both functions RefTypeByVal and RefTypeByRef:

ht = new Hashtable();

Then run the application; you will get the following output:

As you see the count doesn't change after the byVal call because the pointer is overwritten, whilst after the byRef call the count is only 3 not 4 because the reference's reference is overwritten, obviously this is why most of the developers think that the reference types should be passed byRef rather than byValue, especially when the object is overwritten inside the function.

That was a peek into value and reference types, because whilst developers use and instantiate everyday's .NET types they forget the basic concept, so I tried to clear it out in this post, hope you have enjoyed it.!

Labels: