Difference between value types and reference types
(Kristofer Gafvert, January 23, 2005)Introduction
C# provides a set of different data types. The data types in C# are divided into two categories: Value Types and Reference Types. Although there is a third data type: pointers, I will not discuss it here. Pointers can only be used in unsafe code, and as you can figure out by the name, it is not safe and if you can avoid using unsafe code, do it!
A variable that is a value type, stores the data, while a variable of a reference type stores a reference to the data.
Both Value Types and Reference Types have one interesting thing in common; they both derive from System.Object. This is interesting, because most other object oriented languages does not have this behavior. C# is however not the first language, Smalltalk is another language where all objects are derived from a single base class.
Value Types
The value of value types are stored on the managed stack, and can be used directly. This means that the value is stored, and not a reference to the value. This also means that each value type has its own copy of the data. Reference Types on the other hand has a reference to the data, and several variables can reference the same data.
using System; class TestValueTypes { public static void Main() { int a = 5; int b; b = a; Console.WriteLine("a = " + a + "\nb = " + b); a++; Console.WriteLine("We have now increased a with 1"); Console.WriteLine("a = " + a + "\nb = " + b); } }
Output:
a = 5 b = 5 We have now increased a with 1 a = 6 b = 5
To compile this code (if you downloaded it), type:
csc ValueTypes.cs
The above code shows that all value types are working with each own data. The variables "a" and "b" do not reference the same data, ?b? just happen to copy the value of "a". If we draw a picture of this, it would look like this:
Memory for variables allocated on the managed stack is automatically freed when they go out of scope.
Value types always have a value. It might be zero (0), but zero is also a value. For all simple value types, the default value is the value produced by a bit pattern of all zeros. So for sbyte, byte, short, ushort, int, uint, long and ulong the default value is 0. For float it is 0.0f, and for bool it is false. Section 4.1.2 in the C# Language Reference lists all the default values for the value types. The "value" of a value type cannot be null. That is, value types always have a value.
Reference Types
In contrast to value types, the value of a reference types is allocated on the heap. Another name for a reference type, that you might be more familiar with, is an object. Reference types stores the reference to the data, unlike value types, that stores the value. To demonstrate the difference between a reference type and a value type, let's look at this example:
using System; public class Cat { private int age; public void SetAge(int years) { age = years; } public int GetAge() { return age; } } public class RefTest { public static void Main() { Cat miranda = new Cat(); miranda.SetAge(6); Cat caesar = miranda; //caesar now equals miranda Console.WriteLine("Caesar: " + caesar.GetAge()); Console.WriteLine("Miranda: " + miranda.GetAge()); miranda.SetAge(10); //change Miranda's age, what happen to Caesar now? Console.WriteLine("Caesar: " + caesar.GetAge()); Console.WriteLine("Miranda: " + miranda.GetAge()); Console.WriteLine(caesar == miranda); } }
Output:
Caesar: 6 Miranda: 6 Caesar: 10 Miranda: 10 True
To compile this code (if you downloaded it), type:
csc ReferenceType.cs
A class is a reference type, and in the example above I create the class Cat.
As you can see, we do not in any way alter caesar?s age. Despite this, the age is the same as miranda's! This is actually how it is supposed to be, they are "sharing" the same memory. Or, they reference the same data. When we alter the value for one of them, the other will get the same value. The last line verifies that they are the same. We are using the == operator (two equal signs) to check this, and it returns true. We could have also used
Console.WriteLine(Object.ReferenceEquals(caesar, miranda));
to check if they referenced the same memory space.
A picture of this would look like:
For a value type, we do not have this behavior, because in this case the value would have been copied instead of the reference to the value.
Memory for variables that are reference types are not automatically freed when they go out of scope. Instead the Garbage Collector is responsible for this.
In contrast to value types, a reference type does not necessarily have a value. It can be null. This means that the variable does not reference any data.
Cat caesar;
In the above code, caesar does not have a value, and is null.
Applies to [?]
C# 1.1
C# 2.0