C# Concepts - Value Type And Reference Type

This article explains C# concepts of Value and Reference types.

This seems to be a basic but very important part of C# programming.

Value type

 
Value types are generally (not always) stored on the stack and are passed by copying.

The way in which a variable assignment works differs between reference and value types.

If we have something like:
  1. class Program   
  2. {  
  3.     static void Main(string[] args)   
  4.     {  
  5.         A obj1 = new A(12);  
  6.         int v1 = 12;  
  7.         int v2 = 22;  
  8.         v2 = v1;  
  9.         Console.WriteLine(v2);  
  10.         Console.ReadLine();  
  11.     }  
  12. }
Implementation
 
Here, both v1 and v2 will be on the stack and are different entities.

Reference Type

 
A value type is basically stored on the heap and passed by creating a reference.
  1. using System;  
  2. class A {  
  3.     public int value   
  4.     {  
  5.         get;  
  6.         set;  
  7.     }  
  8.     public A(int passbyref)  
  9.     {  
  10.         this.value = passbyref;  
  11.     }  
  12. }  
  13. class Program  
  14. {  
  15.     static void Main(string[] args)  
  16.     {  
  17.         A v1 = new A(12);  
  18.         A v2 = new A(22); //Breakpoint  
  19.         v2 = v1;  
  20.         Console.WriteLine(v1.value);  
  21.         Console.WriteLine(v2.value);  
  22.         Console.ReadLine();  
  23.     }  
  24. }
Implementation
 
v1 and v2 will be on the heap as two entities until a breakpoint.

And after the breakpoint, they both point to one entity.

Figure 1: BreakPoin1

Figure 2: BreakPoint2

So, a change in one will affect the other.

Conclusion

 
Once you pass a value type, you pass a copy to the other method.

But what if we want to change it? Use the “ref” keyword for that.

Suggestion
 
The difference between ref and out should be studied (I will try to write another article for that topic).

Use of ref in value types

 
The ref keyword passes the value by reference (details to be explained later).
  1. class Program   
  2. {  
  3.     static void Main(string[] args)  
  4.     {  
  5.         int v1 = 12;  
  6.         methodtoshowref(ref v1);  
  7.         Console.WriteLine(v1);  
  8.         Console.ReadLine();  
  9.     }  
  10.     public static void methodtoshowref(ref int v2)  
  11.     {  
  12.         v2 = 100;  
  13.     }  
  14. }
Now, v1 becomes 100 because both share the same reference (one entity).

Passing Arguments


We have the following four possibilities:
  1. Pass value type by value.
  2. pass value type by reference
  3. pass reference type by value.
  4. pass reference type by reference.

Pass value type by value

  1. struct A  
  2. {  
  3.     public int val   
  4.     {  
  5.         get;  
  6.         set;  
  7.     }  
  8. }  
  9. class Program   
  10. {  
  11.     static void Main(string[] args)  
  12.     {  
  13.         A v1 = new A();  
  14.         v1.val = 10;  
  15.         methodtoshowref(v1);  
  16.         Console.WriteLine(v1.val);  
  17.         Console.ReadLine();  
  18.     }  
  19.     public static void methodtoshowref(A obj)  
  20.     {  
  21.         obj = new A();;  
  22.     }  
  23. }
Output
 
10 (because one more copy is created and thus the original is not affected).

Pass value type by reference

  1. using System;  
  2. struct A  
  3. {  
  4.     public int val   
  5.     {  
  6.         get;  
  7.         set;  
  8.     }  
  9. }  
  10. class Program  
  11. {  
  12.     static void Main(string[] args)  
  13.     {  
  14.         A v1 = new A();  
  15.         v1.val = 10;  
  16.         methodtoshowref(ref v1);  
  17.         Console.WriteLine(v1.val);  
  18.         Console.ReadLine();  
  19.     }  
  20.     public static void methodtoshowref(ref A obj)   
  21.     {  
  22.         obj = new A();;  
  23.     }  
  24. }
Output
 
0 (since now one copy is shared by both methods).

Pass reference type by value (by default)

  1. using System;  
  2. class A   
  3. {  
  4.     public int val   
  5.     {  
  6.         get;  
  7.         set;  
  8.     }  
  9. }  
  10. class Program  
  11. {  
  12.     static void Main(string[] args)  
  13.     {  
  14.         A v1 = new A();  
  15.         v1.val = 10;  
  16.         methodtoshowref(v1);  
  17.         Console.WriteLine(v1.val);  
  18.         Console.ReadLine();  
  19.     }  
  20.     public static void methodtoshowref(A obj)  
  21.     {  
  22.         obj = null;  
  23.     }  
  24. }
Output
 
10 (this happens because we are passing it by value).

Now here if we do, obj.val=100 then it will print 100 (this is because passing a variable to a function by value is equivalent to instantiating a new variable and assigning it to the first).

More to be discussed in the section on shallow copy vs deep copy (in a later article).
 

Pass reference type by reference

  1. using System;  
  2. class A   
  3. {  
  4.     public int val   
  5.     {  
  6.         get;  
  7.         set;  
  8.     }  
  9. }  
  10. class Program   
  11. {  
  12.     static void Main(string[] args)  
  13.     {  
  14.         A v1 = new A();  
  15.         v1.val = 10;  
  16.         methodtoshowref(ref v1);  
  17.         Console.WriteLine(v1.val);  
  18.         Console.ReadLine();  
  19.     }  
  20.     public static void methodtoshowref(ref A obj)   
  21.     {  
  22.         obj = null;  
  23.     }  
  24. }
Output
 
The error we have now is obj=null so it will give a nullobject error.

Disclaimer - I got inspiration from JonSkeet and various other talented guys.