C#, como muchos lenguajes de tipado estático, proporciona una serie de tipos que representan números enteros, cada uno con su propio rango de valores. En el extremo inferior, el tipo sbyte tiene un valor mínimo de -128 y un valor máximo de 127. Como en todos los tipos enteros, estos valores están disponibles como <type>.MinValue y <type>.MaxValue. En el extremo superior, el tipo long tiene un valor mínimo de -9.223.372.036.854.775.808 y un valor máximo de 9.223.372.036.854.775.807. Entre ambos se encuentran los tipos short e int.
Cada uno de los tipos anteriores se empareja con un equivalente sin signo: sbyte/byte, short/ushort, int/uint y long/ulong. En todos los casos, el rango de valores va de 0 al máximo negativo con signo multiplicado por 2 más 1.
Los valores de los tipos enteros sin signo se representan con una sencilla representación en base 2. Los valores de los tipos con signo utilizan la representación numérica con signo de complemento a dos.
La multiplicidad de tipos enteros refleja las arquitecturas de las máquinas: el tamaño de los registros, el tamaño de los argumentos de las instrucciones de la CPU y el tratamiento del signo dentro de la CPU. Un valor de tipo long usa 64 bits, mientras que un valor de tipo sbyte usa 8 bits. En algunos casos esto tendrá implicaciones en el rendimiento de la CPU, el uso de memoria e incluso el uso de disco (donde elegir un tipo entero más pequeño suele ser beneficioso). Elegir el type de número entero también puede ser una manera aproximada de comunicar a otros desarrolladores el rango de valores esperado. El tipo int se usa ampliamente como tipo predeterminado cuando no se ha identificado nada especial sobre el uso concreto. El long o ulong se usa ampliamente como identificador sencillo. El tamaño del tipo en bytes determina el rango de valores.
Los tipos vistos hasta ahora son tipos primitivos. Cada uno se empareja con un alias struct que implementa campos (como MinValue) y métodos (como ToString()) que están asociados al tipo.
| Tipo | Estructura | Ancho | Mínimo | Máximo |
|---|---|---|---|---|
sbyte |
SByte |
8 bits | -128 | +127 |
short |
Int16 |
16 bits | -32_768 | +32_767 |
int |
Int32 |
32 bits | -2_147_483_648 | +2_147_483_647 |
long |
Int64 |
64 bits | -9_223_372_036_854_775_808 | +9_223_372_036_854_775_807 |
byte |
Byte |
8 bits | 0 | +255 |
ushort |
UInt16 |
16 bits | 0 | +65_535 |
uint |
UInt32 |
32 bits | 0 | +4_294_967_295 |
ulong |
UInt64 |
64 bits | 0 | +18_446_744_073_709_551_615 |
Una variable (o expresión) de un tipo se puede convertir fácilmente a otro. Por ejemplo, en una operación de asignación, si el tipo del valor que se asigna (lado derecho) garantiza que el valor cabe dentro del rango del tipo al que se asigna (lado izquierdo), la asignación es simple:
ulong ul;
uint ui = uint.MaxValue;
ul = ui; // no problem
Por otro lado, si el rango del tipo desde el que se asigna no es un subconjunto del rango de valores del tipo al que se asigna, se requiere una operación de conversión, (), incluso si el valor concreto está dentro del rango del tipo de destino:
uint ui;
short s = 42;
ui = (uint)s;
En el ejemplo anterior, si el valor estuviera fuera del rango del tipo de destino, se produciría un desbordamiento. Consulta overflow.
La necesidad de conversión la determinan los dos tipos implicados, y no un valor concreto.
Los siguientes párrafos tratan la conversión de los tipos enteros. (consulta casting) ofrece un análisis más amplio de la conversión de tipos. Consulta esa documentación para ver un análisis de la conversión entre tipos enteros y números de coma flotante, char y bool.
El sistema de tipos de C# es algo más estricto que el de C o el de JavaScript y, en consecuencia, las operaciones de conversión están más restringidas. La conversión implícita se produce entre dos tipos numéricos siempre que el tipo «de destino» pueda conservar la escala y el signo del valor del tipo «de origen».
Una conversión implícita no se indica con ninguna sintaxis especial.
Cuando los tipos numéricos no se pueden convertir implícitamente, por lo general puedes usar el operador de conversión explícita.
Cuando el valor que se convierte no puede representarse con el tipo «de destino» porque no es lo bastante ancho o hay un conflicto de signo, se puede producir una excepción de desbordamiento.
int largeInt = Int32.MaxValue;
int largeNegInt = Int32.MinValue;
ushort shortUnsignedInt = ushort.MaxValue;
// implicit cast
int from_ushort = shortUnsignedInt; // 65535
float from_int = largeInt; // -21474836E+09
// explicit cast
uint from_largeInt = (uint)largeInt; // 2147483647
uint from_neg = (uint) largeNegInt; // 2147483648 or OverflowException is thrown (if checked)
La clase BitConverter ofrece una forma cómoda de convertir tipos enteros a arrays de bytes y viceversa.