Data Types in C#

Sunday 12 June 2016

Data Types in C#


Three fundamental data types of c# are value types, reference type and pointer types.Value types are created on stack and reference types are created on heap. Reference type variables hold the  reference of data stored and value types holds the actual value. A pointer is nothing but a variable that holds the memory address of another type. But in C# pointer can only be declared to hold the memory address of value types and arrays. Unlike reference types, pointer types are not tracked by the default
garbage collection mechanism. For the same reason pointers are not allowed to point to a reference type or even to a structure type which contains a reference type. If the data in the memory location is changed by one of the variables, the other variable automatically reflects this change in value. Defaults values of different value type are different like boolean default value is false, decimal 0. Similarly default value of reference type variable is always null. Primitive types (except strings), enumerations, and structures are value
types. Classes, strings, interfaces, arrays, and delegates are reference types.

The following table lists the available value types in C#
Type Represents                  Range        Default Value
bool       Boolean value            True or False           False
byte       8-bit unsigned integer         0 to 255             0
char    16-bit Unicode character  U +0000 to U +ffff            '\0'
decimal 128-bit precise decimal    (-7.9 x 1028 to 7.9 x 1028)    0.0M
       values with 28-29 significant     / 100 to 28
              digits       
double 64-bit double-precision   (+/-)5.0 x 10-324 to      0.0D
           floating point type          (+/-)1.7 x 10308
 float 32-bit single-precision
           floating point type          -3.4 x 1038 to + 3.4 x 1038    0.0F
int 32-bit signed integer type          -2,147,483,648 to 2,147,483,647    0
long 64-bit signed integer type          -9,223,372,036,854,775,808 to       0L
                                9,223,372,036,854,775,807
sbyte 8-bit signed integer type               -128 to 127             0
short 16-bit signed integer type -32,768 to 32,767                    0
uint 32-bit unsigned integer type     0 to 4,294,967,295                     0
ulong 64-bit unsigned integer type 0 to 18,446,744,073,709,551,615 0
ushort 16-bit unsigned integer type 0 to 65,535                    0

Enumerations (Value Type)

If you have a number of constants that are logically related to each other, then you can group together these constants in an enumeration.Enumeration provides
efficient way to assign multiple constant integral values to a single variable. Enumeration improves code clarity and makes program easier to maintain.
Enumeration in C# also provides more security by better error-checking technology and compiler warnings.
The default underlying type of the enumeration elements is int. By default, the first enumerator has the value 0, and the value of each successive enumerator
is increased by 1. enum Dow {Sat, Sun, Mon, Tue, Wed, Thu, Fri};
Some points about enum:
enums are enumerated data type in c#.
enums are not for end-user, they are meant for developers.
enums are strongly typed constant. They are strongly typed, i.e. an enum of one type may not be implicitly assigned to an enum of another type even though the
underlying value of their members are the same.
Enumerations (enums) make your code much more readable and understandable.
enum values are fixed. enum can be displayed as a string and processed as an integer.
The default type is int, and the approved types are byte, sbyte, short, ushort, uint, long, and ulong.
Every enum type automatically derives from System.Enum and thus we can use System.Enum methods on enums.

using System;

namespace Enumeration
{
  // creating enumeration for storing day.
  public enum attandance
   {
     Monday,
     Tuesday,
     Wednesday,
     Thursday,
     Friday
   }

  class Program
   {
     static void Main(string[] args)
      {
        attandance present = attandance.Monday;//Valid
        Console.WriteLine(present);
         
        //attandance absent = attandance.Sunday;//Invalid
        Console.ReadLine();
      }
   }
}

Strings (Reference Type) and chars 

The string is a data type representing textual data in computer programs. A string in C# is a sequence of Unicode characters. A char is a single Unicode character.
using System;

class Strings
{
    static void Main()
    {
        string word = "India";

        char c = word[0];

        Console.WriteLine(c);
    }
}
Output :
The program prints 'I' character to the terminal.


Arrays (Reference Type)

The array is a complex data type which handles a collection of elements. Each of the elements can be accessed by an index. All the elements of an array must be of
the same data type.
using System;

class ArrayExample
{
    static void Main()
    {      
        int[] numbers = new int[5];

        numbers[0] = 3;
        numbers[1] = 2;
        numbers[2] = 1;
        numbers[3] = 5;
        numbers[4] = 6;

        int len = numbers.Length;

        for (int i=0; i<len; i++)
        {
            Console.WriteLine(numbers[i]);
        }
    }
}
Output :
3 2 1 5 6

DateTime (Value Type)

The DateTime is a value type. It represents an instant in time, typically expressed as a date and time of day.
using System;

class DateTimeExample
{
    static void Main()
    {
        DateTime today;

        today = DateTime.Now;

        System.Console.WriteLine(today);
     }
}
Output :
06/12/2016 10:56:37 AM

Nullable types (Reference Type)

Value types cannot be assigned a null literal, reference types can. Applications that work with databases deal with the null value. Because of this, special nullable
types were introduced into the C# language. Nullable types are instances of the System.Nullable<T> struct.
using System;

class NullableType
{
    static void Main()
    {
        Nullable<bool> male = null;
        Console.WriteLine(male.HasValue);
     
    }
}
Output :
False

Pointer type  

The general form of declaring a pointer type is as shown below      
type *variable_name;
Where * is known as the de-reference operator. For example the following statement
int *x ;
Declares a pointer variable x, which can hold the address of an int type. The reference operator (&) can be used to get the memory address of a variable.
int x = 100;
The &x gives the memory address of the variable x, which we can assign to a pointer variable
int *ptr = & x;.
Console.WriteLine((int)ptr) // Displays the memory address
Console.WriteLine(*ptr) // Displays the value at the memory address.
We can say that pointers can point to only unmanaged types which includes all basic data types, enum types, other pointer types and structs which contain
only unmanaged types.

Boxing & UnBoxing

C# allows us to convert a Value Type to a Reference Type, and back 
again to Value Types . The operation of Converting a Value Type to a Reference Type is called Boxing and the reverse operation is called Unboxing.boxing is 
Implicit Conversion and Unboxing is Explicit Conversion.

C# Type System contains three Types , they are Value Types , Reference Types and Pointer Types. C# allows us to convert a Value Type to a Reference Type, and back 
again to Value Types . The operation of Converting a Value Type to a Reference Type is called Boxing and the reverse operation is called Unboxing.boxing is 
Implicit Conversion and Unboxing is Explicit Conversion.
Boxing

  1: int Val = 1;
  2: Object Obj = Val; //Boxing

The first line we created a Value Type Val and assigned a value to Val. The second line , we created an instance of Object Obj and assign the value of Val to Obj.
From the above operation (Object Obj = i ) we saw converting a value of a Value Type into a value of a corresponding Reference Type . These types of operation is
called Boxing.

UnBoxing

  1: int Val = 1;
  2: Object Obj = Val; //Boxing
  3: int i = (int)Obj; //Unboxing

The first two line shows how to Box a Value Type . The next line (int i = (int) Obj) shows extracts the Value Type from the Object . That is converting a value of a
Reference Type into a value of a Value Type. This operation is called UnBoxing.

Boxing and UnBoxing are computationally expensive processes. When a value type is boxed, an entirely new object must be allocated and constructed , also the cast
required for UnBoxing is also expensive computationally.

Memory Consumption
When you declare an elementary data type, it is not safe to assume that its memory consumption is the same as its nominal storage allocation.
This is due to the following considerations:
Storage Assignment. The common language runtime can assign storage based on the current characteristics of the platform on which your application is executing. If memory is nearly full, it might pack your declared elements as closely together as possible. In other cases it might align their memory addresses to natural hardware boundaries to optimize performance.
Platform Width. Storage assignment on a 64-bit platform is different from assignment on a 32-bit platform.
Composite Data Types
The same considerations apply to each member of a composite data type, such as a structure or an array. You cannot rely on simply adding together the nominal storage allocations of the type's members. Furthermore, there are other considerations, such as the following:
Overhead. Some composite types have additional memory requirements. For example, an array uses extra memory for the array itself and also for each dimension. On a 32-bit platform, this overhead is currently 12 bytes plus 8 bytes for each dimension. On a 64-bit platform this requirement is doubled.
Storage Layout. You cannot safely assume that the order of storage in memory is the same as your order of declaration. You cannot even make assumptions about byte alignment, such as a 2-byte or 4-byte boundary. If you are defining a class or structure and you need to control the storage layout of its members, you can apply the StructLayoutAttribute attribute to the class or structure.