C# has the predefined numeric types shown in the following Table.
Integral-signed
C# type | System type | Suffix | Size | Range |
---|---|---|---|---|
sbyte | SByte | No Suffix | 8 bits | -27 to 27-1 |
short | Int16 | No Suffix | 16 bits | -215 to 215-1 |
int | Int32 | No Suffix | 32 bits | -231 to 231-1 |
long | Int64 | L | 64 bits | -263 to 263-1 |
Integral-unsigned
C# type | System type | Suffix | Size | Range |
---|---|---|---|---|
byte | Byte | No Suffix | 8 bits | 0 to 28-1 |
ushort | UInt16 | No Suffix | 16 bits | 0 to 216-1 |
uint | UInt32 | U | 32 bits | 0 to 232-1 |
ulong | UInt64 | UL | 64 bits | 0 to 264-1 |
Real
C# type | System type | Suffix | Size | Range |
---|---|---|---|---|
float | Single | F | 32 bits | +/- (~10-45 to 1038) |
double | Double | D | 64 bits | +/- (~10-324 to 10308) |
decimal | Decimal | M | 128 bits | +/- (~10-28 to 1028) |
The decimal type is typically used for financial calculations.
Integral literals can use decimal or hexadecimal notation; hexadecimal is denoted
with the 0x
prefix. For example:
int x = 1;
long y = 0x7F;
Real literals can use decimal and/or exponential notation. For example:
double d = 1.5;
double million = 1E06;
By default, the compiler infers a numeric literal to be either double or an integral type:
If the literal contains a decimal point or the exponential symbol (E), it is a double.
The literal's type is the first type in this list that can fit the literal's value: int, uint, long, and ulong.
For example:
Console.WriteLine ( 1.0.GetType()); // Double (double)
Console.WriteLine ( 1E06.GetType()); // Double (double)
Console.WriteLine ( 1.GetType()); // Int32 (int)
Console.WriteLine ( 0xF0000000.GetType()); // UInt32 (uint)
Numeric suffixes explicitly define the type of a literal.
Suffixes can be either lower or uppercase, and are as follows:
Category | C# type | Example |
---|---|---|
F | float | float f = 1.0F; |
D | double | double d = 1D; |
M | decimal | decimal d = 1.0M; |
U | uint | uint i = 1U; |
L | long | long i = 1L; |
UL | ulong | ulong i = 1UL; |
The F
and M
suffixes should always be applied when specifying
float or decimal literals.
Without the F
suffix, the following line would not
compile, because 4.5 would be inferred to be of type double, which has no implicit
conversion to float:
float f = 4.5F;
The same principle is applied for a decimal literal:
decimal d = -1231.13M; // Will not compile without the M suffix.
Integral conversions are implicit when the destination type can represent every possible value from the source type. Otherwise, an explicit conversion is required.
For example:
int x = 12345; // int is a 32-bit integral
long y = x; // Implicit conversion to 64-bit integral
short z = (short)x; // Explicit conversion to 16-bit integral
A float can be implicitly converted to a double, since a double can represent every possible value of a float.
The reverse conversion must be explicit.
All integral types may be implicitly converted to all floating-point types:
int i = 1;
float f = i;
The reverse conversion must be explicit:
int i2 = (int)f;
When you cast from a floating-point number to an integral, any fractional portion is truncated(lost).
All integral types can be implicitly converted to the decimal type.
All other numeric conversions to and from a decimal type must be explicit.