Value And Reference Types
Date posted: 03/11/2012
You haven't filled in compulsory values.
The email is not correct
Introduction
Every variable created in a .Net application can be either of value or reference type. C#'s value type consist of most basic types such as all numeric types, bools, enums and structs. All other types, such as strings, classes, interfaces etc, are reference types. At first you may guess that value types are simpler than reference types. A class for example can be much more complex than an integer. You may be right. However the actual reason we use this division, is the way such value types are copied, as well as the way they are stored in memory. Let's take a look at the memory part first.
Memory allocation
Supposing we declare an integer.
int ValueTypeInteger = 0;
What would we need to store its value? Just a single slot in memory where we will store 0 (and the variable's name). Now what if we had a class like this?
class ReferenceTypeClass
//Random class containing integer value
{
int _ReferenceTypeClass_Int;
public int ReferenceTypeClass_Int
{
get { return _ReferenceTypeClass_Int; }
set { _ReferenceTypeClass_Int = value; }
}
}
The obvious answer, one slot, would be incorrect. What would happen if a class contained additional classes? That would make things much more complex and difficult to handle. Instead, programming architects have come up with the idea of using a different way to store types. Value types are stored in the stack and reference types are stored in the heap.
Stack is simply a stack, a part of the memory which we handle like a LIFO data structure. When we create a value type variable, a part of the stack-memory is fetched in order to store its value. When we create the next variable, the following part is fetched. Remember, the stack is just a stack. Our variables will look somewhat like this.
int int1 = 0;
int int2 = 1;
The stack can contain no more the 1MB of info. This may seem enough to store thousands of values containing a few bytes of info. But what if there was a class containing other classes? Or what would you do if a simple string had to fit more than 1MB of info?
As a result, the heap was created. The heap is a location in the memory where we store reference types. Actually, there may be occasions where we store value types in the heap as well (for example when a class contains value types), but this is not how it usually works.
ReferenceTypeClass object1= new ReferenceTypeClass();
To store an object in the heap we would first have to create a reference in the stack, pointing to the heap. In other words, when we create an instance of the class, a place in the stack is used as a guide to the location of the heap where the values of the class are stored. A look in the following image will make things much clearer.
When a reference type object is created, a reference is created in the stack. When it is initialized the object is placed in the heap.
When the method called is done, the stack will be released of its unwanted piece of information. On the other hand, the heap will be cleared and organized later on by the garbage collector.
Copying values
Ok then, we got to know what the stack and the heap are. What does this have to do with actual programming however? Earlier we mentioned that it has to do with the way values are copied. When we copy a value type variable to another, the second variable's value will be a copy of the first one's.
private void ValueTypes()
{
//Value types are stored separately
int int1 = 0;
int int2 = int1;
int1 = 1;
int2 = 2;
}
At the end of the method, int1 will be 1 and int2 will be 2. Integer is a value type. Let's check out the stack.
Now, it's time to try out the same thing in a reference value, a class.
private void ReferenceTypes()
{
//Reference types will be stored in the same location in the heap
ReferenceTypeClass object1 = new ReferenceTypeClass();
ReferenceTypeClass object2 = object1;
object1.ReferenceTypeClass_Int = 1;
object2.ReferenceTypeClass_Int = 2;
}
At the end of the method, both object1's as well as object2's ReferenceTypeClass_Int will be 2.Why is that? When copying object1 to object2 we do not copy each value, we just copy the reference in the stack. So now we have two points in the stack aiming at the same point in the heap. Every change in the first object will change the heap. However the second object is also looking at the same memory part. So, at the moment the command object1.ReferenceTypeClass_Int = 1; is run, both object1.ReferenceTypeClass_Int and object2.ReferenceTypeClass_Int will become 1. Running object2.ReferenceTypeClass_Int = 2; will result in their turning into 2.
Now, we will try to nullify the second object and see what will happen to the first copied object.
private void ReferenceTypesNull()
{
//Setting object2 to null will not affect object1
ReferenceTypeClass object1 = new ReferenceTypeClass();
ReferenceTypeClass object2 = object1;
object2 = null;
}
At the end of the method, object2 will be null, but object1 won't. When nullifying object2 what we actually do, is to set the stack reference to null. Object2 no loger points to the heap object. However object1 is not affected at all by this. It is still pointing to the heap. If there was only one slot in the stack pointing at the heap, and we turned that into null, then the object in the heap would be useless, as we would not be able to access it. In that case the garbage collector would show up and release that heap location.
Call by value
The default way of applying arguments to a method is calling by value. Arguments applied this way will not be subject to changes; instead a copy will be created to the stack, containing the argument's value. If the argument is of value type, a complete copy will be created and whatever changes may happen will affect the copy. If the argument is of reference type, a reference copy will be created in the stack pointing to the object in the heap. So we will have two objects pointing to the same values. As a result, changes applied to the second object will affect the original copy as well.
We now have a value type integer and a reference type class and a method that uses call by value.
int valueTypeInteger = 0;
ReferenceTypeClass referenceObject = new ReferenceTypeClass();
private void CallByValue(int int1, ReferenceTypeClass object1)
{
//Integer will remain intact while class value will change
int1 = 1;
object1.ReferenceTypeClass_Int = 1;
}
Prior to calling CallByValue we have
valueTypeInteger = 0
referenceObject.ReferenceTypeClass_Int = 0
After calling CallByValue(ValueTypeInteger, referenceObject) we have
valueTypeInteger = 0
referenceObject.ReferenceTypeClass_Int = 1
The integer is unaffected by the call, while the class' property has changed. The following image makes things clearer.
However the next method will not affect the argument ReferenceTypeClass object.
private void ClassByValueToNull(ReferenceTypeClass object1)
{
//Argument will remain intact
object1 = null;
}
Turning the new object into null will not affect the heap but rather remove the stack copy pointing to the heap.
Call by reference
We've just examined how calling by value works. Now it's time to check out call by reference. When calling a method this way we do not create a copy, rather than a reference to the stack value, whatever it may be. So, using call by reference to a value type will create a reference to the value in the stack, thus making it possible to change its value. Call by reference to a reference value will result in being able to change the reference in the stack, thus allowing us to change the object's value as well as its reference.
private void CallByReference(ref int int1, ref ReferenceTypeClass object1)
{
//Both value and reference types will change
int1 = 1;
object1.ReferenceTypeClass_Int = 1;
}
Prior to calling CallByReference we have
valueTypeInteger = 0
referenceObject.ReferenceTypeClass_Int = 0
After calling CallByReference(ValueTypeInteger, referenceObject) we have
valueTypeInteger = 1
referenceObject.ReferenceTypeClass_Int = 1
Let's try again the previous example. We tried to delete a reference type object using call by value. However, we will now use call by reference.
private void ClassByReferenceToNull(ref ReferenceTypeClass object1)
{
//Argument will be null
object1 = null;
}
After calling this method, the argument object will become null. Removing the reference, there are no object values associated with it any longer.
Conclusion
There are two kinds of type in .Net applications. Value and reference types. Value types point straight to their values while reference types contain an indirect reference and use different approach when copying values. Typically value types are stored in the stack, while reference types are held in the heap. Arguments in a method can be either called by value or by reference causing different effects depending on their nature.
Back to BlogPreviousNext