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.