Because the type system in C# is unified with other languages that are CLI-compliant, each integral C# type is actually an alias for a corresponding type in the .NET framework. Although the names of the aliases vary between .NET languages, the underlying types in the .NET framework remain the same. Thus, objects created in assemblies written in other languages of the .NET Framework can be bound to C# variables of any type to which the value can be converted, per the conversion rules below. The following illustrates the cross-language compatibility of types by comparing C# code with the equivalent Visual Basic .NET code:
// C#
public void UsingCSharpTypeAlias()
{
int i = 42;
}
public void EquivalentCodeWithoutAlias()
{
System.Int32 i = 42;
}
Visual Basic .NET
Public Sub UsingVisualBasicTypeAlias()
Dim i As Integer = 42
End Sub
Public Sub EquivalentCodeWithoutAlias()
Dim i As System.Int32 = 42
End Sub
Using the language-specific type aliases is often considered more readable than using the fully-qualified .NET Framework type names.
The fact that each C# type corresponds to a type in the unified type system gives each value type a consistent size across platforms and compilers. That consistency is an important distinction from other languages such as C, where, e.g. a long is only guaranteed to be at least as large as an int, and is implemented with different sizes by different compilers. As reference types, variables of types derived from object (i.e. any class) are exempt from the consistent size requirement. That is, the size of reference types like System.IntPtr, as opposed to value types like System. Int, may vary by platform. Fortunately, there is rarely a need to know the actual size of a reference type.
There are two predefined reference types: object, an alias for the System.Object class, from which all other reference types derive; and string, an alias for the System.String class. C# likewise has several integral value types, each an alias to a corresponding value type in the System namespace of the .NET Framework. The predefined C# type aliases expose the methods of the underlying .NET Framework types. For example, since the .NET Framework's System.Int32 type implements a ToString() method to convert the value of an integer to its string representation,
C#'s int type exposes that method:
int i = 97;
string s = i.ToString();
// The value of s is now the string "97".
Likewise, the System.Int32 type implements the Parse() method, which can therefore be accessed via C#'s int type:
string s = "97";
int i = int.Parse(s);
// The value of i is now the integer 97.
The unified type system is enhanced by the ability to convert value types to reference types (boxing) and likewise to convert certain reference types to their corresponding value types (unboxing). This is also known as casting.
object boxedInteger = 97;
int unboxedInteger = (int)boxedInteger;
Boxing and casting are, however, not type-safe: the compiler won't generate an error if the programmer mixes up the types. In the following short example the mistake is quite obvious, but in complex programs it may be real hard to spot. Avoid boxing, if possible.
object getInteger = "97";
int anInteger = (int)getInteger; // no compile-time error, the program will crash, however The built-in C# type aliases and their equivalent .NET Framework types follow:
Integers
C# Alias .NET Type Size (bits) Range
sbyte System.SByte 8 -128 to 127
byte System.Byte 8 0 to 255
short System.Int16 16 -32,768 to 32,767
ushort System.UInt16 16 0 to 65,535
char System.Char 16 A unicode character of code 0 to 65,535
int System.Int32 32 -2,147,483,648 to 2,147,483,647
uint System.UInt32 32 0 to 4,294,967,295
long System.Int64 64 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
ulong System.UInt64 64 0 to 18,446,744,073,709,551,615
Floating-point
C# Alias .NET Type Size (bits) Precision Range
float System.Single 32 7 digits 1.5 x 10-45 to 3.4 x 1038
double System.Double 64 15-16 digits 5.0 x 10-324 to 1.7 x 10308
decimal System.Decimal 128 28-29 decimal places 1.0 x 10-28 to 7.9 x 1028
Other predefined types
C# Alias .NET Type Size (bits) Range
bool System.Boolean 32 true or false, which aren't related to any integer in C#.
object System.Object 32/64 Platform dependant (a pointer to an object).
string System.String 16 * length A unicode string with no special upper bound.
// C#
public void UsingCSharpTypeAlias()
{
int i = 42;
}
public void EquivalentCodeWithoutAlias()
{
System.Int32 i = 42;
}
Visual Basic .NET
Public Sub UsingVisualBasicTypeAlias()
Dim i As Integer = 42
End Sub
Public Sub EquivalentCodeWithoutAlias()
Dim i As System.Int32 = 42
End Sub
Using the language-specific type aliases is often considered more readable than using the fully-qualified .NET Framework type names.
The fact that each C# type corresponds to a type in the unified type system gives each value type a consistent size across platforms and compilers. That consistency is an important distinction from other languages such as C, where, e.g. a long is only guaranteed to be at least as large as an int, and is implemented with different sizes by different compilers. As reference types, variables of types derived from object (i.e. any class) are exempt from the consistent size requirement. That is, the size of reference types like System.IntPtr, as opposed to value types like System. Int, may vary by platform. Fortunately, there is rarely a need to know the actual size of a reference type.
There are two predefined reference types: object, an alias for the System.Object class, from which all other reference types derive; and string, an alias for the System.String class. C# likewise has several integral value types, each an alias to a corresponding value type in the System namespace of the .NET Framework. The predefined C# type aliases expose the methods of the underlying .NET Framework types. For example, since the .NET Framework's System.Int32 type implements a ToString() method to convert the value of an integer to its string representation,
C#'s int type exposes that method:
int i = 97;
string s = i.ToString();
// The value of s is now the string "97".
Likewise, the System.Int32 type implements the Parse() method, which can therefore be accessed via C#'s int type:
string s = "97";
int i = int.Parse(s);
// The value of i is now the integer 97.
The unified type system is enhanced by the ability to convert value types to reference types (boxing) and likewise to convert certain reference types to their corresponding value types (unboxing). This is also known as casting.
object boxedInteger = 97;
int unboxedInteger = (int)boxedInteger;
Boxing and casting are, however, not type-safe: the compiler won't generate an error if the programmer mixes up the types. In the following short example the mistake is quite obvious, but in complex programs it may be real hard to spot. Avoid boxing, if possible.
object getInteger = "97";
int anInteger = (int)getInteger; // no compile-time error, the program will crash, however The built-in C# type aliases and their equivalent .NET Framework types follow:
Integers
C# Alias .NET Type Size (bits) Range
sbyte System.SByte 8 -128 to 127
byte System.Byte 8 0 to 255
short System.Int16 16 -32,768 to 32,767
ushort System.UInt16 16 0 to 65,535
char System.Char 16 A unicode character of code 0 to 65,535
int System.Int32 32 -2,147,483,648 to 2,147,483,647
uint System.UInt32 32 0 to 4,294,967,295
long System.Int64 64 -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
ulong System.UInt64 64 0 to 18,446,744,073,709,551,615
Floating-point
C# Alias .NET Type Size (bits) Precision Range
float System.Single 32 7 digits 1.5 x 10-45 to 3.4 x 1038
double System.Double 64 15-16 digits 5.0 x 10-324 to 1.7 x 10308
decimal System.Decimal 128 28-29 decimal places 1.0 x 10-28 to 7.9 x 1028
Other predefined types
C# Alias .NET Type Size (bits) Range
bool System.Boolean 32 true or false, which aren't related to any integer in C#.
object System.Object 32/64 Platform dependant (a pointer to an object).
string System.String 16 * length A unicode string with no special upper bound.