C# Concepts: Value Type and Reference Type

This seems to be a basic but very 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.

Refrence 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.