O C#, tal como muitas linguagens com tipos estáticos, disponibiliza vários tipos que representam números inteiros, cada um com o seu próprio intervalo de valores. No extremo inferior, o tipo sbyte tem um valor mínimo de -128 e um valor máximo de 127. Tal como em todos os tipos de inteiros, estes valores estão disponíveis como <type>.MinValue e <type>.MaxValue. No extremo superior, o tipo long tem um valor mínimo de -9 223 372 036 854 775 808 e um valor máximo de 9 223 372 036 854 775 807. Entre estes encontram-se os tipos short e int.
Cada um dos tipos acima tem um equivalente sem sinal: sbyte/byte, short/ushort, int/uint e long/ulong. Em todos os casos, o intervalo de valores vai de 0 até ao máximo com sinal negativo, multiplicado por 2 e somado a 1.
Os valores dos tipos inteiros sem sinal são representados com uma simples representação em base 2. Os valores dos tipos com sinal usam a representação de números com sinal em complemento de dois.
A multiplicidade de tipos de inteiros reflete as arquiteturas das máquinas, no tamanho dos registos, no tamanho dos argumentos das instruções da CPU e no tratamento do sinal dentro da CPU. Um valor do tipo long usa 64 bits, enquanto um valor do tipo sbyte usa 8 bits. Em alguns casos, haverá implicações no desempenho da CPU, no uso de memória e até no uso de disco (em que a escolha de um tipo de inteiro mais pequeno será, em geral, benéfica). A escolha do type para um inteiro pode também ser uma forma rápida e simples de comunicar aos outros programadores informação sobre o intervalo de valores esperado. O tipo int é amplamente utilizado como tipo predefinido quando nada de especial se identificou na utilização em causa. O long ou o ulong são amplamente utilizados como um simples identificador. O tamanho do tipo em bytes determina o intervalo de valores.
Os tipos abordados até aqui são tipos primitivos. Cada um está associado a um alias struct que implementa campos (como MinValue) e métodos (como ToString()) associados ao tipo.
| Tipo | Estrutura | Largura | 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 |
Uma variável (ou expressão) de um tipo pode ser facilmente convertida noutro tipo. Por exemplo, numa operação de atribuição, se o tipo do valor que está a ser atribuído (lado direito) garantir que o valor cabe no intervalo do tipo de destino (lado esquerdo), basta uma atribuição simples:
ulong ul;
uint ui = uint.MaxValue;
ul = ui; // no problem
Por outro lado, se o intervalo do tipo de origem não for um subconjunto do intervalo de valores do tipo de destino, é necessária uma conversão explícita, a operação (), mesmo que o valor em causa esteja dentro do intervalo do destino:
uint ui;
short s = 42;
ui = (uint)s;
No exemplo acima, se o valor estivesse, em vez disso, fora do intervalo do tipo de destino, ocorreria um overflow. Vê overflow.
A necessidade de conversão é determinada pelos dois tipos envolvidos e não por um valor em particular.
Os parágrafos seguintes abordam a conversão de tipos inteiros. casting apresenta uma discussão mais ampla sobre conversão e conversão de tipos. Consulta essa documentação para uma discussão sobre a conversão entre tipos inteiros e números de vírgula flutuante, char e bool.
O sistema de tipos do C# é um pouco mais rigoroso do que o do C ou o do JavaScript e, por consequência, as operações de conversão são mais restritas. A conversão implícita ocorre entre dois tipos numéricos desde que o tipo de destino consiga preservar a escala e o sinal do valor do tipo de origem.
Uma conversão implícita não é indicada por nenhuma sintaxe especial.
Quando os tipos numéricos não podem ser convertidos implicitamente, podes, em geral, usar o operador de conversão explícita.
Quando o valor a converter não pode ser representado pelo tipo de destino, por não ser suficientemente largo ou por haver um conflito de sinal, pode ser lançada uma exceção de overflow.
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)
A classe BitConverter oferece uma forma cómoda de converter tipos inteiros de e para arrays de bytes.