Intrinsic types

A value type is a data type which is either one of the intrinsic built-in types, a structure or an enumeration. The intrinsic built-in types are the most commonly used data types, such as int or double.
The following table lists some of the built-in value types and includes links to MSDN for reference. The first eight types are used for whole number values and the last three represent real numbers in order of increasing precision.
Default Values Table
C# Type .NET Framework Type CLS-Compliant Description
byte System.Byte Yes 8 bit unsigned integer
sbyte System.SByte No 8 bit signed integer
short System.Int16 Yes 16 bit signed integer
ushort System.UInt16 No 16 bit unsigned integer
int System.Int32 Yes 32 bit signed integer
uint System.UInt32 No 32 bit unsigned integer
long System.Int64 Yes 64 bit signed integer
ulong System.UInt64 No 64 bit unsigned integer
float System.Single Yes 32 bit; IEEE comform Floating-Point-Value
double System.Double Yes 64 bit; IEEE comform Floating-Point-Value
decimal System.Decimal Yes 128 bit Floating-Point-Value
(1 bit sign; 96 bit value; 8 bit exponent; 23 bit unused)
The table shows that each of the built-in types is an alias of the .NET Framework System types. For example, int is an alias of System.Int32. To convert one data type to another requires a cast to be performed.
Two other notewothy value types that are commonly used are:
Default Values Table
C# Type .NET Framework Type CLS-Compliant Description
bool System.Boolean Yes 1 bit; represents true or false
char System.Char Yes 16 bit Unicode character
A value type variable exists on the stack from the point it is declared until it goes out of scope. For example, when a method returns, all of the local variables inside the method are removed from the stack. In addition, a value type can also exist within an object as one of the object's data members. In that case, its scope is tied to the object that contains it.

Declaring value types

A value type can be declared without being initialized, however it cannot be used unless a value is assigned to it. For example the following code will cause an error of type "Use of unassigned local variable".
public int foo()
{
int a;
return a;
}
This is because the value of a value type cannot contain the value null. If this is required, use a nullable type instead.
This can be overcome in two ways. The first is simply to assign a value at declaration:
public int foo()
{
int a = 12;
return a;
}
The second way is through the use of the new keyword. When a value type is created using the new keyword, its value will default to a known state by its default constructor.
Each value type has an implicit default constructor that initializes the default value of that particular type. For information on the default values of value types, refer to the Default Values Table.
public int foo()
{
int a = new int(); // Default value of 0
return a;
}


Copying value types

When one value type variable is assigned to another, the value is copied. This can be seen in the following example:
// Declare and initialize a to 10
int a = 10;
 
// Declare and initialize b to a (10)
int b = a;
 
// a is now 15, but b is still 10
a = 15;
The second statement declares a new integer named b and assigns it to a. The value of a is passed to b as a copy of the original value. Now when a is altered in the third statement, it has no effect on the value of b.


Passing parameters by value

When you pass a variable to a method, this means you are passing a copy of the variable to the method. Any change to the parameter that takes place inside the method has no effect on the original data stored in the variable. In the following example, the value of myInt will still be five after the method has been called.
public void SquareIt(int x) { x *= x; }
 
public static void Main()
{
int myInt = 5;
SquareIt(myInt); // Passing myInt by value.
}


Passing parameters by reference

If you want the called method to change the value of the parameter, you have to pass it by reference, using the ref or out keywords. In the following example, the value of myInt will equal 25 after the method has been called.
public void SquareIt(ref int x) { x *= x; }
 
public static void Main()
{
int myInt = 5;
SquareIt(ref myInt); // Passing myInt by reference.
}


Visual C# Best Practices

You should mark functions explicitly which are using non-CLR Types with System.CLSCompliantAttribute.
[CLSCompliant(false)]
public ushort foo() { ... }
This will generate a warning message when compiling, which makes it possible to find otherwise hidden interop-errors when you working on a .Net Project using various Programming-Languages which are originally not created for .Net.


MSDN references