Introduction
It is very important to have a clear understanding of the data types available in c# in order to write code for application. The data types in C# are divided into two categories – Value Types and Reference Types. Here i am going to describe the value type and reference type with example and when we should use what. The code snippet is written in c#.Main
What is Value type?
Value type variables directly contain values. Assigning one value type variable to another copies the contained value. All numeric types, ints, floats and doubles along with enums, chars, bools and structs are value types
What is Reference type?
Variables of reference types, referred to as objects, store references to the actual data rather than the data itself. Class, interface, delegate, object and string are reference type.
Memory Allocation:
Common Language Runtime (CLR) allocates memory for objects in two places: the stack and the heap. The stack is a simple last-in first-out (LIFO) memory structure, and is highly efficient. Series of boxes can be treated as stack. We can only use what is in the top box on the stack. That means when we execute any method, we are dealing top most box in the stack but once a method execution is over, we throw it away and proceed to use the stuff in the previous box on the top of the stack. So method pushes data onto the stack as it executes and pops all the method’s memory allocations after the method is done executing. On the otherhand, the heap can be pictured as a random muddle of objects. Unlike stack anything in heap can be accessed at any time. Heap allows objects to be allocated or deallocated in a random order. CLR deals with the two in different ways. When a value-type instance is created, a single space in memory is allocated to store the value in stack. Reference types store the address of their data on the stack .The actual data that address refers to is stored in an area of memory called the heap. Code Listing 1
struct ValTyp
{
private int x, y;public ValTyp(int a, int b)
{
this.x = a;this.y = b;
}
public int X
{
get { return x; }
set { x = value; }
}
public int Y
{
get { return y; }
set { y = value; }
}
}
class RefTyp
{
int x;int y;public RefTyp()
{
}
public int X
{
get { return x; }
set { x = value;}
}
public int Y
{
get { return y; }
set { y = value; }
}
}
ValTyp vt=new ValTyp();
RefTyp rt=new rt();In the above code listing for the 1st line (vt is a struct and rt is a class), one space in memory is allocated for vt, and in the 2nd line, two spaces are allocated: one for a RefTyp object and another for its reference (rt):
RefTyp rt; // Allocate the reference in memory
rt=new rt(); // Allocate the object in memory
If we copy the objects to new variables:
ValTyp vt1=vt;
RefTyp rt1=rt;
vt1 is a struct which is an independent copy of vt, with its own separate fields. But in the case of rt, all we have copied is a reference and both rt and rt1 point to the same object. In C#, parameters are passed by value by default, meaning that they are implicitly copied when passed to the method. For value-type parameters we copy the instance physically like vt is copied into vt1 , while for reference-types we copy a reference like rt1 is a reference of rt. Here is an example:
Code Listing 2 ValTyp myValTyp = new ValTyp (0, 0);
Reftyp myReftyp = new Reftyp ();
Test (myValTyp , myReftyp)
void Test (ValTyp VT, Reftyp RT)
{
VT.X = 100;
RT.X = 100;
VT = null;
}
Here is the explanation of the above code: There is no effect on myValTyp since VT is a copy. This will change myReftyp since myReftyp and RT both point to the same object. Assigning null to VT has no effect on myValTyp because VT is a copy of a reference, and we have only erased the copy. Parameters can be passed by reference and when we are passing parameter by reference, the method interacts directly with the caller’s arguments.
Code Listing 3 Test (ref myValTyp ,ref myReftyp);void Test (ref ValTyp VT, ref Reftyp RT)
{
VT.X = 100;
RT.X = 100;
RT = null;
}
Here is the explanation of the above code:
This will change myValTyp //First line.
This will change myReftyp //Second Line.
In this case, assigning null to RT also makes myReftyp null, because this time we are dealing with the original reference variable and not a copy of it.
Disposal: Once use of reference type variable is over, its local stack-allocated variable will disappear from scope and be popped off the stack. And for disposal of orphaned object ( because stack-allocated object which was pointing the object in heap is no longer present) on the heap, the Common Language Runtime’s garbage collector (GC) comes into play. Once our program reaches a certain memory threshold and we need more heap space, our GC will find all objects in the heap that are not being referenced that means orphaned and delete them. The GC will then reorganize all the remaining objects in the heap to make and adjust space. For value type there is no role of CLR to clean up memory. Memory is cleaned automatically when value type variable finished execution.
Boxing and Unboxing:
Boxing is a mechanism for converting value types to reference types. Unboxing is a mechanism for converting reference types to value types. In the following example, the integer variable iCnt is boxed and assigned to object objX.
Code Listing 4int iCnt = 101;
object objX = (object)iCnt; // boxing
Response.Write(iCnt); // 101
objX = 201;
iCnt = (int)objX; // unboxing
Response.Write(iCnt); // 201
Compare to simple assignments, boxing and unboxing are expensive processes. When a value type is boxed, a new object must be allocated and constructed. To a lesser degree, the type casting required for unboxing is also expensive .
Differences: Value Type Reference Type
1. stored on the stack. stored on the heap.
2. can not contain the value null. can contain the value null.
3. have default value. default to a null reference in memory. 4.derive from System.ValueType. derive from System.Object.
5. Value types cannot derive a new type from an existing can derive a new type from an
existing value type, except for
structs. reference type and also Implicitly
sealed, means no class can derive from them.
able to implement interfaces.
6.not under garbage collector Under Garbage Collector
What to use? Value types or reference types? Structs or classes? When should we use what? The right choice depends on how we expect to use the new type. They are better suited to store the data. Unlike value type reference types can be polymorphic and should be used to define the behavior of our application. Structs store data. Classes define behavior. It is also true that value types are more efficient in terms of memory management. Value types have very limited support for common object-oriented techniques. We can not create object hierarchies of value types. We can create value types that implement interfaces, but that requires boxing and thus performance issue rises.
Conclusion Concept of value type and reference type is very useful for beginners. We should build data storage types as value types and build the behavior of our application using reference types. Value types are lighter than reference types.