C#, comme beaucoup de langages à typage statique, fournit un certain nombre de types qui représentent des entiers, chacun avec sa propre plage de valeurs. En bas de l'échelle, le type sbyte a une valeur minimale de -128 et une valeur maximale de 127. Comme pour tous les types entiers, ces valeurs sont disponibles via <type>.MinValue et <type>.MaxValue. En haut de l'échelle, le type long a une valeur minimale de -9,223,372,036,854,775,808 et une valeur maximale de 9,223,372,036,854,775,807. Entre les deux se trouvent les types short et int.
Chacun des types ci-dessus est associé à un équivalent non signé : sbyte/byte, short/ushort, int/uint et long/ulong. Dans tous les cas, la plage de valeurs va de 0 à l'opposé du maximum signé multiplié par 2, plus 1.
Les valeurs des types entiers non signés sont représentées par une simple représentation en base 2. Les valeurs des types signés utilisent la représentation signée en complément à deux.
La multiplicité des types entiers reflète les architectures matérielles : la taille des registres, la taille des arguments des instructions du processeur et le traitement du signe au sein du processeur. Une valeur de type long utilise 64 bits, alors qu'une valeur de type sbyte en utilise 8. Dans certains cas, cela a des conséquences sur les performances du processeur, l'utilisation de la mémoire et même l'espace disque (où le choix d'un type entier plus petit est généralement bénéfique). Le choix du type entier peut aussi être un moyen simple, sinon approximatif, de communiquer aux autres développeurs la plage de valeurs attendue. Le type int est largement utilisé comme type par défaut quand rien de particulier n'a été identifié dans l'usage concerné. Le long ou l'ulong est largement utilisé comme simple identifiant. La taille du type en octets détermine la plage de valeurs.
Les types dont on a parlé jusqu'ici sont des types primitifs. Chacun est associé à un alias struct qui implémente les champs (comme MinValue) et les méthodes (comme ToString()) liés à ce type.
| Type | Struct | Taille | Minimum | Maximum |
|---|---|---|---|---|
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 |
Une variable (ou une expression) d'un type donné peut facilement être convertie en un autre type. Par exemple, dans une affectation, si le type de la valeur affectée (à droite) garantit que cette valeur tiendra dans la plage du type de destination (à gauche), l'affectation est directe :
ulong ul;
uint ui = uint.MaxValue;
ul = ui; // no problem
En revanche, si la plage du type source n'est pas un sous-ensemble de la plage de valeurs du type de destination, une opération de cast () est nécessaire, même si la valeur en question se situe dans la plage du type de destination :
uint ui;
short s = 42;
ui = (uint)s;
Dans l'exemple ci-dessus, si la valeur se trouvait plutôt en dehors de la plage du type de destination, un dépassement de capacité se produirait. Voir overflow.
La nécessité de caster dépend des deux types impliqués, et non d'une valeur particulière.
Les paragraphes suivants traitent du cast des types entiers. La page casting propose une discussion plus large du cast et de la conversion de types. Consulte cette documentation pour une discussion sur la conversion entre types entiers et nombres à virgule flottante, char et bool.
Le système de types de C# est un peu plus strict que celui du C ou de Javascript, et par conséquent les opérations de cast y sont plus limitées. Le cast implicite a lieu entre deux types numériques tant que le type de destination peut préserver l'échelle et le signe de la valeur du type source.
Un cast implicite n'est signalé par aucune syntaxe particulière.
Quand des types numériques ne peuvent pas être castés implicitement, on peut généralement utiliser l'opérateur de cast explicite.
Si la valeur castée ne peut pas être représentée par le type de destination, parce qu'il n'est pas assez large ou qu'il y a un conflit de signe, une exception de dépassement de capacité peut être levée.
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 classe BitConverter offre un moyen pratique de convertir des types entiers vers des tableaux d'octets et inversement.