Showing posts with label Value Types vs. reference types. Show all posts
Showing posts with label Value Types vs. reference types. Show all posts

Sunday, February 26, 2012

Arrays and Arraylist in .NET

So far we have been discussing the fundamentals of object oriented programming, difference between interfaces, abstract classes, enumerations, structures etc. Today, we will talk about using arrays and arraylists to store various objects and difference between the two.

Both arrays and arraylists are stored on a heap. Even if you store value types in an array or an arraylist, the values are implicitly converted to reference types (boxing) and you must explicitly convert them back to proper value types (unboxing) when using them.

Since the items stored in an array or an array list are objects, you can use them to also store reference to objects. For example,

consider the following class...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApp1
{
    class Student
    {
      
     private string _name;
     private string _address;
     private int _studentID;
     public string Name
     {
          get {return _name;}
          set {_name=value;}
     }
     public string Address
     {
          get {return _address;}
          set {_address=value;}
     }
     public int StudentID
     {
          get {return _studentID;}
          set {_studentID=value;}
     }
  }
    
}

Now let's use an array to store several references of these objects.

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //Using an Array
 
            //first instance
             Student student1 = new Student();
             student1.Name = "Student One";
             student1.Address = "123, Peachtree Road, Atlanta, GA 30303";
             student1.StudentID = 1;
            //second instance
             Student student2 = new Student();
             student2.Name = "Student Two";
             student2.Address = "456, Peachtree Road, Atlanta, GA 30303";
             student2.StudentID = 2;
            //third instance
             Student student3 = new Student();
             student3.Name = "Student Three";
             student3.Address = "678, Peachtree Road, Atlanta, GA 30303";
             student3.StudentID = 3;

             //instantiate an array to store these objects.
             Student[] StudentsList = new Student[2];
             StudentsList[0] = student1;
             StudentsList[1] = student2;
             StudentsList[2] = student3;

            //since array is already of type Student, no typecasting is necessary.
            Console.WriteLine(StudentsList[0]);

       }
    }
}

There are several problems with this approach. First, you have to initialize an array and specify its size. Which means you have to know how many objects you are going to store in an array beforehand. Second limitation is that an array must be specific to the type you are going to store, meaning you cannot store two different types of objects in an array. Also, once an array has been initialized to a specific size, you cannot resize it downwards.

Now let's consider the same example using an arraylist.

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
             
            //first instance
             Student student1 = new Student();
             student1.Name = "Student One";
             student1.Address = "123, Peachtree Road, Atlanta, GA 30303";
             student1.StudentID = 1;
            //second instance
             Student student2 = new Student();
             student2.Name = "Student Two";
             student2.Address = "456, Peachtree Road, Atlanta, GA 30303";
             student2.StudentID = 2;
            //third instance
             Student student3 = new Student();
             student3.Name = "Student Three";
             student3.Address = "678, Peachtree Road, Atlanta, GA 30303";
             student3.StudentID = 3;

            //instantiate an arraylist to store these objects.
             ArrayList StudentList = new ArrayList();   
            
            // notice an arraylist isn't of a specifc type.
             StudentList.Add(student1);
             StudentList.Add(student2);
             StudentList.Add(student3);

            //since arraylist is a generic list, you must type cast it first.
            Console.WriteLine((Student)(StudentList[0]));

            //Arraylist allows for inserting an object at a specific position.

             //fourth instance
             Student student4 = new Student();
             student4.Name = "Student Four";
             student4.Address = "890, Peachtree Road, Atlanta, GA 30303";
             student4.StudentID = 4;
             StudentList.Insert(1, student4);

            //You can also remove an object from an array list
             StudentList.Remove(student4); // remove a specific object
            //OR
             StudentList.RemoveAt(2);   //remove whatever is at index 2
     
        }
    }
}

As you can see, an arraylist avoids some of the problems of an array. First, an arraylist doesn't have to be sized and resized. An element can be added or removed from an arraylist.

Note, since an arraylist isn't cast into a specific type during declaration, when reading the content from an arraylist, you must explicitly cast to a specific type, as show in the above code snippet.

An arraylist also allows for inserting an object at any position, including the position where an object may already exist. If you insert an element at a position already occupied by another element, the current element will simply push down.

Since an arraylist isn't of a particular type, you can add elements of reference or value types in an array, even mixing them.

For example you can do the following.

StudentList[0] = student1;
StudentList[1] = 5;
StudentList[2] = "This is a test";
StudentList[3] = student2;

But if you add objects of different types or value types in the same arraylist, you must first inspect the element to determine its type before casting it to the appropriate type. This is not only cumbersome and error prone, it also adds an unnecessary overhead.

To write out the content from the above example, you now have to do the following...

if (StudentList[1].GetType() == typeof(int))
   {
    //do something
   }

This becomes unusable pretty quickly. So, what should you do to get the flexibility of an arraylist without the added overhead? In the next post we will talk about generic collections and how they can aid us in a situation like this.

Tuesday, February 14, 2012

Value Types Vs Reference Types in .NET


Before we dive into the value types or reference types definition, let's take a step back and understand what happens when you declare a variable .NET.

Anytime you declare a variable, some memory is allocated to this variable. There are three pieces of information that is stored in memory - the variable name, its datatype and the value it contains. The variable is stored on one of the two types of memory - Stack and Heap.

When you declare a variable which is of value type (I know I am jumping ahead), some memory is allocated. When you declare another variable of the value type, another chunk of memory is allocated which is stacked on top of the first allocation and so forth. Think of stacks as just boxes stacked on top of one another. For value types the memory is allocated statically. For example, 4 bytes of memory is allocated to a variable of type Int.

Memory is allocated on a first come first serve basis but it is de-allocated in the reverse order i.e. Last In First Out (LIFO). Think of it as you are stacking boxes on top of each other and to remove them, you have to remove the last one first and so on.

When you create a variable of type reference, the object itself is allocated on another type of memory called "Heap". Just as the name suggests, heap is just a collection of reference type variables (also commonly called objects) and there is no particular order. A pointer to these reference type variables is stored on stack.

Memory De-Allocation
When you exit a method or a class where you instantiated and consumed these variables, memory is de-allocated in the following fashion

  • Stack is cleared first in LIFO order.
  • Heap is not cleared - Garbage Collector will clear it at some point
You may be wondering why value types are stored on stack and reference types are stored on heap?

The reason primarily has to do with the complexity. Value types are primitive data types such as Integer, Byte, SByte etc. and framework knows in advance how much memory to allocate when they are initialized. Reference types such as objects on the other hand are complex types. An object may have an instance of another object etc. which means the memory must be dynamically allocated, hence they are stored on a heap.

Another point to note is that all variables must be declared and instantiated, but .NET framework automatically instantiates the value types.

For example - 
int i = new int(5);  
can also be declared as int i = 5;

All reference types with the exception of String must be explicitly instantiated (unless your classes are declared as static/shared).

For example
Person clsPerson = new Person();

Value Types
  • All Numeric Data Types 
    • E.g. integer, byte, sbyte, short, Decimal, Double etc.
  • Variables of type Boolean, Char and Date
  • Enumerations
    • Since the underlying types for enumerators can only be of value type.
  • Structs / Structures
Reference Types
  • String
  • Arrays (even if their elements are value types)
  • Classes / Forms.
  • Delegates

In the future post we will discuss the concept of boxing and unboxing and the difference between structures and classes and performance impacts of using one over the other.

Thank you and as always, your comments are welcome!