Types primitifs et variables
Les types primitifs sont les types de données élémentaires suivants : bool, ushort, uint, int, ulong, long, byte, sbyte, float, double, decimal et char. Ces types primitifs correspondent aux classes Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double et Single. Ainsi, on peut donc traiter les types primitifs comme des objets en utilisant le tableau de référence suivant :
Type primitif | Classe correspondante |
---|---|
bool | Boolean |
byte | Byte |
sbyte | SByte |
char | Char |
short | Int16 |
int | Int32 |
long | Int64 |
ushort | UInt16 |
uint | UInt32 |
ulong | UInt64 |
float | Single |
double | Double |
decimal | Decimal |
Qu'est-ce qu'une variable ?
Un programme typique utilise diverses valeurs changeant pendant son exécution. Par exemple, nous créons un programme effectuant des calculs sur les valeurs saisies par l'utilisateur. Les valeurs saisies par un utilisateur seront évidemment différentes de celles saisies par un autre utilisateur. Cette situation signifie que lors de la création du programme, le programmeur ne sait pas quelles valeurs seront introduites en entrée, et cela rend nécessaire de traiter toutes les valeurs possibles qu'un utilisateur peut entrer. Lorsqu'un utilisateur entre une nouvelle valeur étant utilisée dans le processus de calcul, nous pouvons la conserver (temporairement) dans la mémoire vive de notre ordinateur. Les valeurs de cette partie de la mémoire changent (varient) tout au long de l'exécution et cela a conduit à leur nom : variables.
Types de données
Les types de données sont des ensembles (intervalles) de valeurs ayant des caractéristiques similaires. Par exemple, le type d'octet spécifie l'ensemble des nombres entiers compris entre [0...255]. Les types de données sont caractérisés par : leur nom (par exemple, int), leur taille (combien de mémoire ils utilisent, par exemple, 4 octets) et leur valeur (par défaut, par exemple 0). Les types de données de base en C# sont répartis dans les types suivants :
Catégorie | Types de données |
---|---|
Types entiers | sbyte, byte, short, ushort, int, uint, long, ulong |
Types réels à virgule flottante | float, double |
Type réel avec précision décimale | decimal |
Type booléen | bool |
Type de caractère | char |
Chaîne de caractères | string |
Type d'objet | object |
Ces types de données sont appelés primitifs (types intégrés), car ils sont incorporés dans le langage de programmation C# au niveau le plus bas. Le tableau suivant représente les types de données mentionnés ci-dessus, leur intervalles et leurs valeurs par défaut :
Types de données | Valeur par défaut | Valeur minimum | Valeur maximum |
---|---|---|---|
sbyte | 0 | -128 | 127 |
byte | 0 | 0 | 255 |
short | 0 | -32768 | 32767 |
ushort | 0 | 0 | 65535 |
int | 0 | -2147483648 | 2147483647 |
uint | 0u | 0 | 4294967295 |
long | 0L | -9223372036854775808 | 9223372036854775807 |
ulong | 0u | 0 | 18446744073709551615 |
float | 0.0f | ±1.5×10-45 | ±3.4×1038 |
double | 0.0d | ±5.0×10-324 | ±1.7×10308 |
decimal | 0.0m | ±1.0×10-28 | ±7.9×1028 |
bool | false | Deux valeurs possibles : true et false | |
char | '\u0000' | '\u0000' | '\uffff' |
object | null | - | - |
string | null | - | - |
Correspondance entre les types C# et .NET
Les types de données primitifs en C# ont une correspondance directe avec les types du système de type commun (CTS) dans le cadre d'application .NET. Par exemple, le type int en C# correspond au type System.Int32 en CTS et au type Integer en langage de programmation VB.NET, tandis que le type long en C# correspond au type System.Int64 en CTS et au type Long en langage de programmation VB.NET. En raison du système de types communs (CTS) dans le cadre d'application .NET, il existe une compatibilité entre différents langages de programmation (comme par exemple, C#, Managed C++, VB.NET et F#). Pour la même raison, les types int, Int32 et System.Int32 en C# sont en fait des alias différents pour un seul et même type de données - un entier de 32 bits signé.
Types entiers
Les types entiers représentent des nombres entiers et sont sbyte, byte, short, ushort, int, uint, long et ulong. Examinons-les un par un. Le type sbyte est un entier signé de 8 bits. Cela signifie que le nombre de valeurs possibles est de 28, soit 256 valeurs au total, et elles peuvent être à la fois positives et négatives. La valeur minimale pouvant être entreposée dans sbyte est SByte.MinValue = -128 (-27) et la valeur maximale est SByte.MaxValue = 127 (27-1). La valeur par défaut est le nombre 0. Le type d'octet est un type entier non signé 8 bits. Il a également 256 valeurs entières différentes (28) ne pouvant être que non négatives. Sa valeur par défaut est le nombre 0. La valeur minimale prise est Byte.MinValue = 0 et la valeur maximale est Byte.MaxValue = 255 (28-1). Le type short est un entier signé 16 bits. Sa valeur minimale est Int16.MinValue = -32768 (-215) et la valeur maximale est Int16.MaxValue = 32767 (215-1). La valeur par défaut du type short est le nombre 0. Le type ushort est un entier non signé de 16 bits. La valeur minimale qu'il peut entreposer est UInt16.MinValue = 0 et la valeur minimale est UInt16.MaxValue = 65535 (216-1). Sa valeur par défaut est le nombre 0. Le prochain type entier que nous considérerons est int. C'est un entier signé de 32 bits. Comme nous pouvons le constater, la croissance des bits augmente les valeurs possibles qu'un type peut entreposer. La valeur par défaut de int est 0. Sa valeur minimale est Int32.MinValue = -2 147 483 648 (-231) et sa valeur maximale est Int32.MaxValue = 2 147 483 647 (231-1). Le type int est le type le plus souvent utilisé en programmation. Habituellement, les programmeurs utilisent int lorsqu'ils travaillent avec des entiers car ce type est naturel pour le microprocesseur 32 bits et est suffisamment gros pour la plupart des calculs effectués dans la vie quotidienne. Le type uint est de type entier non signé 32 bits. Sa valeur par défaut est le nombre 0u ou 0U (les deux sont équivalents). La lettre «u» indique que le nombre est de type uint (sinon, il est compris comme int). La valeur minimale qu'il peut prendre est UInt32.MinValue = 0 et la valeur maximale est UInt32.MaxValue = 4 294 967 295 (232-1). Le type long est un type signé 64 bits avec une valeur par défaut de 0l ou 0L (les deux sont équivalents mais il est préférable d'utiliser 'L' car la lettre 'l' est facilement confondue avec le chiffre un '1'). La lettre 'L' indique que le nombre est de type long (sinon il est compris int). La valeur minimale pouvant être entreposée dans le type long est Int64.MinValue = -9 223 372 036 854 775 808 (-263) et sa valeur maximale est Int64.MaxValue = 9 223 372 036 854 775 807 (263-1). Le plus grand type entier est le type ulong. C'est un type non signé de 64 bits, ayant comme valeur par défaut - le nombre 0u ou 0U (les deux sont équivalents). Le suffixe «u» indique que le nombre est de type ulong (sinon il est entendu comme long). La valeur minimale pouvant être enregistrée dans le type ulong est UInt64.MinValue = 0 et la valeur maximale est UInt64.MaxValue = 18 446 744 073 709 551 615 (264-1). Prenons un exemple dans lequel nous déclarons plusieurs variables des types entiers que nous connaissons, nous les initialisons et affichons leurs valeurs sur la console :
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace integersamples
- {
- class Program
- {
- static void Main(string[] args)
- {
- byte siecle = 20;
- ushort annees = 2020;
- uint jours = 737300;
- ulong heures = 17695200;
-
- Console.WriteLine("Au " + siecle + " siècle, dans l'année " + annees + ", soit " + jours + " jours, ou " + heures + " heures.");
-
- ulong maxIntValue = UInt64.MaxValue;
- Console.WriteLine(maxIntValue);
- }
- }
- }
Types de données réels à virgule flottante
Les types réels en C# sont les nombres réels comme nous les connaissons grâce dans les sciences des mathématiques. Ils sont représentés par une virgule flottante selon la norme IEEE 754 et sont float et double. Examinons en détail ces deux types de données et comprenons quelles sont leurs similitudes et leurs différences.
Type réel Float
Le premier type que nous considérerons est le type de données à virgule flottante réel de 32 bits. Il est également connu sous le nom de nombre réel à de simple précision. Sa valeur par défaut est 0,0f ou 0,0F (les deux sont équivalents). Le caractère 'f' lorsqu'il est placé à la fin indique explicitement que le nombre est de type float (car par défaut tous les nombres réels sont considérés comme double). Le type considéré a une précision jusqu'à sept décimales (les autres sont perdues). Par exemple, si le nombre 0.123456789 est entreposé sous le type float, il sera arrondi à 0.1234568. L'intervalle de valeurs, pouvant être incluse dans un type de données à virgule flottante (arrondi avec une précision de 7 chiffres décimaux significatifs), va de ±1,5 × 10-45 à ±3,4 × 1038. Les types de données réels ont également plusieurs valeurs spéciales n'étant pas des nombres réels mais sont des abstractions mathématiques :
- Infini négatif -∞ (Single.NegativeInfinity). Il est obtenu lorsque, par exemple, nous divisons -1,0f par 0,0f.
- Infini positif +∞ (Single.PositiveInfinity). Il est obtenu lorsque, par exemple, nous divisons 1,0f par 0,0f.
- Incertitude (Single.NaN) - signifie qu'une opération invalide est effectuée sur des nombres réels. Il est obtenu lorsque, par exemple, nous divisons 0,0f par 0,0f, ainsi que lors du calcul de la racine carrée d'un nombre négatif.
Type de données réel Double
Le deuxième type de donnée réel à virgule flottante dans le langage de programmation C# est le type de donnée double. Il est également appelé nombre réel de double précision et est de type de 64 bits avec une valeur par défaut de 0,0d et 0,0D (le suffixe 'd' n'est pas obligatoire car par défaut tous les nombres réels en C# sont de type de donnée double). Ce type de donnée a une précision de 15 à 16 chiffres décimaux. L'intervalle de valeurs, pouvant être enregistrée en double (arrondie avec une précision de 15 à 16 chiffres décimaux significatifs), va de ± 5,0 × 10-324 à ± 1,7 × 10308. La plus petite valeur réelle de type de données double est la constante Double.MinValue = -1,79769e+308 et la plus grande est Double.MaxValue = 1,79769e+308. Le nombre positif le plus proche de 0 de type de données double est Double.Epsilon = 4.94066e324. Comme pour le type de donnée float, les variables de type de données double peuvent prendre les 116 principes fondamentaux de la programmation informatique spéciaux avec des valeurs C# : Double.PositiveInfinity (+∞), Double.NegativeInfinity (-∞) et Double.NaN (nombre invalide). Voici un exemple dans lequel nous déclarons des variables de types de nombres réels, leur attribuons des valeurs et les affichons :
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace RealSamples
- {
- class Program
- {
- static void Main(string[] args)
- {
- float floatPI = 3.14159f;
- Console.WriteLine(floatPI); // Nombre 3,14159
- double doublePI = 3.14159;
- Console.WriteLine(doublePI); // 3,14159
- double nan = Double.NaN;
- Console.WriteLine(nan); // NaN
- double infinity = Double.PositiveInfinity;
- Console.WriteLine(infinity); // Infini
- }
- }
- }
Précision des types de données réels
En mathématiques, les nombres réels dans une intervalles donnée sont innombrables (par opposition aux nombres entiers de cette intervalle) car entre deux nombres réels a et b, il y a d'innombrables autres nombres réels c où a < c < b. Cette situation nécessite que les nombres réels soient entreposés dans la mémoire de l'ordinateur avec une précision limitée. Puisque les mathématiques et la physique fonctionnent principalement avec des nombres extrêmement grands (positifs et négatifs) et avec des nombres extrêmement petits (très proches de zéro), les types de données réels dans les périphériques informatiques et électroniques doivent être entreposés et traités de manière appropriée. Par exemple, selon la physique, la masse de l'électron est d'environ 9,109389 × 10-31 kilogrammes et dans 1 mole de substance, il y a environ 6,02 × 1023 atomes. Ces deux valeurs peuvent être stockées facilement dans les types float et double. En raison de sa flexibilité, la représentation moderne en virgule flottante des nombres réels nous permet de travailler avec un nombre maximum de chiffres significatifs pour de très grands nombres (par exemple, des nombres positifs et négatifs avec des centaines de chiffres) et avec des nombres très proches de zéro (par exemple, des nombres positifs et négatifs avec des centaines de zéros après la virgule décimale avant le premier chiffre significatif). Les nombres réels à virgule flottante en C # se composent de trois composants (selon la norme IEEE 754): signe (1 ou -1), mantisse et ordre (exposant), et leurs valeurs sont calculées par une formule complexe. Dans les calculs avec des types de données réels à virgule flottante, il est possible d'observer un comportement étrange, car lors de la représentation d'un nombre réel donné, il arrive souvent à perdre en précision. La raison en est l'incapacité de certains nombres réels à être représentés exactement comme une somme de puissances négatives du nombre 2. De plus, tous les nombres réels n'ont pas une représentation précise dans les types float et double. Par exemple, le nombre 0,1 est représenté arrondi en type float comme 0,099999994.
Voici un exemple de précision des types de données réels :
- using System;
-
- class Program {
- static void Main() {
- // Déclaration des variables
- float floatValue = 1.0f / 3.0f; // Division avec précision float
- double doubleValue = 1.0 / 3.0; // Division avec précision double
- decimal decimalValue = 1.0m / 3.0m; // Division avec précision decimal
-
- // Afficher les valeurs
- Console.WriteLine("Précision des types réels en C# :");
- Console.WriteLine($"Valeur float : {floatValue}"); // 7 chiffres significatifs
- Console.WriteLine($"Valeur double : {doubleValue}"); // 15-16 chiffres significatifs
- Console.WriteLine($"Valeur decimal: {decimalValue}"); // 28-29 chiffres significatifs
-
- // Test de sommation pour observer les erreurs d'accumulation
- float floatSum = 0f;
- double doubleSum = 0.0;
- decimal decimalSum = 0.0m;
-
- // Ajouter une petite valeur plusieurs fois
- for (int i = 0; i < 1000000; i++) {
- floatSum += 0.000001f;
- doubleSum += 0.000001;
- decimalSum += 0.000001m;
- }
-
- Console.WriteLine("\nAprès une accumulation répétée (1 000 000 additions) :");
- Console.WriteLine($"Somme float : {floatSum}"); // Erreurs d'arrondi visibles
- Console.WriteLine($"Somme double : {doubleSum}"); // Erreurs d'arrondi minimes
- Console.WriteLine($"Somme decimal: {decimalSum}"); // Aucune erreur d'arrondi
- }
- }
Types réels avec précision décimale
Le langage de programmation C# prend en charge l'arithmétique dite décimale à virgule flottante, où les nombres sont représentés via le système numérique décimal plutôt que le système binaire. Ainsi, le type arithmétique décimal à virgule flottante en C# ne perd pas de précision lors de l'entreposage et du traitement des nombres à virgule flottante. Le type de données pour les nombres réels avec une précision décimale en C# est le type décimal de 128 bits. Il a une précision de 28 à 29 décimales. Sa valeur minimale est -7,9 × 1028 et sa valeur maximale est + 7,9 × 1028. La valeur par défaut est 0,0 m ou 0,0 m. Le caractère 'm' à la fin indique explicitement que le nombre est de type décimal (car par défaut tous les nombres réels sont de type double). Les nombres les plus proches de 0, pouvant être enregistrés en décimal, sont ± 1,0 × 10-28. Il est évident que le décimal ne peut entreposer ni de très gros nombres positifs ou négatifs (par exemple, avec des centaines de chiffres), ni des valeurs très proches de 0. Cependant, ce type est presque parfait pour les calculs financiers car il représente les nombres comme une somme de puissances de 10 et les pertes d'arrondi sont beaucoup plus petites que lors de l'utilisation de la représentation binaire. Les nombres réels de type décimal sont extrêmement pratiques pour les calculs financiers - calcul des revenus, droits, taxes, intérêts, paiements,...
- using System;
-
- class Program {
- static void Main() {
- // Types réels en C#
- float floatValue = 3.1415927f; // Précision simple (7 chiffres significatifs)
- double doubleValue = 3.141592653589793; // Précision double (15-16 chiffres significatifs)
- decimal decimalValue = 3.1415926535897932384626433832m; // Haute précision (28-29 chiffres significatifs)
-
- // Afficher les valeurs
- Console.WriteLine($"Valeur float : {floatValue}");
- Console.WriteLine($"Valeur double : {doubleValue}");
- Console.WriteLine($"Valeur decimal : {decimalValue}");
-
- // Comparaison de précision
- double circleRadius = 1.23456789;
- double circleAreaDouble = Math.PI * Math.Pow(circleRadius, 2); // Utilisation de double
- decimal circleAreaDecimal = (decimal)Math.PI * (decimal)Math.Pow(circleRadius, 2); // Conversion pour decimal
-
- Console.WriteLine($"\nAire d'un cercle avec double : {circleAreaDouble}");
- Console.WriteLine($"Aire d'un cercle avec decimal : {circleAreaDecimal}");
- }
- }
Type de données booléen
Le type de données booléen est déclaré avec le mot clef bool. Il a deux valeurs possibles : true et false. Sa valeur par défaut est false. Il est le plus souvent utilisé pour entreposer le résultat du calcul des expressions logiques. On l'utilise également pour entreposer des résultats d'opérateur ternaire.
- using System;
-
- class Program {
- static void Main() {
- // Déclaration et initialisation d'un booléen
- bool isRaining = true;
- bool isSunny = false;
-
- // Afficher les valeurs booléennes
- Console.WriteLine($"Est-ce qu'il pleut ? {isRaining}");
- Console.WriteLine($"Est-ce qu'il fait soleil ? {isSunny}");
-
- // Utilisation dans une condition
- if (isRaining) {
- Console.WriteLine("Prenez un parapluie !");
- } else {
- Console.WriteLine("Pas besoin de parapluie.");
- }
-
- // Combinaison logique
- bool shouldGoOutside = !isRaining && isSunny;
- Console.WriteLine($"Peut-on aller dehors ? {shouldGoOutside}");
-
- // Utilisation avec une expression
- int temperature = 25;
- bool isWarm = temperature > 20;
- Console.WriteLine($"Est-ce qu'il fait chaud ? {isWarm}");
- }
- }
Type de données de caractère
Le type de données caractère est un caractère unique (numéro 16 bits d'un caractère de table Unicode). Il est déclaré en C# avec le mot-clef char. La table Unicode est un standard technologique représentant n'importe quel caractère (lettre, ponctuation,...) de toutes les langues humaines en tant que systèmes d'écriture (toutes langues et alphabets) avec un entier ou une séquence d'entiers. La plus petite valeur possible d'une variable char est 0 et la plus grande est 65535. Les valeurs de type char sont des lettres ou d'autres caractères et sont entourées d'apostrophes.
Voici un exemple de manipulation d'un caractère :
- using System;
-
- class Program {
- static void Main() {
- // Déclaration et initialisation d'un caractère
- char letter = 'A';
-
- // Afficher le caractère
- Console.WriteLine($"Caractère : {letter}");
-
- // Vérifier si le caractère est une lettre
- bool isLetter = char.IsLetter(letter);
- Console.WriteLine($"Est une lettre ? {isLetter}");
-
- // Vérifier si le caractère est une majuscule
- bool isUpper = char.IsUpper(letter);
- Console.WriteLine($"Est en majuscule ? {isUpper}");
-
- // Convertir en minuscule
- char lower = char.ToLower(letter);
- Console.WriteLine($"En minuscule : {lower}");
-
- // Vérifier si le caractère est un chiffre
- char digit = '5';
- bool isDigit = char.IsDigit(digit);
- Console.WriteLine($"'{digit}' est un chiffre ? {isDigit}");
-
- // Valeur Unicode du caractère
- int unicodeValue = (int)letter;
- Console.WriteLine($"Valeur Unicode de '{letter}' : {unicodeValue}");
- }
- }
Les chaînes de caractères
Les chaînes de caractères sont des séquences de caractères. En C#, ils sont déclarés par le mots-clefs string. Leur valeur par défaut est null. Les chaînes de caractères sont placées entre doubles guillemets. Différentes opérations de traitement de texte peuvent être effectuées à l'aide de chaînes de caractères : concaténation (jonction d'une chaîne de caractères à une autre), fractionnement par un séparateur donné, recherche, remplacement de caractères et autres.
Voici un exemple simple d'utilisation du type string en C# :
- using System;
-
- class Program {
- static void Main() {
- // Déclaration et initialisation d'une chaîne
- string greeting = "Bonjour";
-
- // Concaténation de chaînes
- string name = "Jinny";
- string message = greeting + ", " + name + "!";
- Console.WriteLine(message); // Affiche : Bonjour, Jinny!
-
- // Longueur de la chaîne
- Console.WriteLine($"La longueur du message est : {message.Length}");
-
- // Accéder à un caractère par son index
- Console.WriteLine($"Premier caractère : {message[0]}");
-
- // Transformation en majuscules
- string uppercaseMessage = message.ToUpper();
- Console.WriteLine($"En majuscules : {uppercaseMessage}");
-
- // Vérifier si une chaîne contient un mot
- bool containsAlice = message.Contains("Jinny");
- Console.WriteLine($"Le message contient 'Jinny' ? {containsAlice}");
-
- // Diviser une chaîne de caractères
- string[] words = message.Split(' ');
- Console.WriteLine("Les mots du message sont :");
- foreach (string word in words) {
- Console.WriteLine(word);
- }
- }
- }
Voici un second exemple d'utilisation de string :
- using System;
-
- class Program {
- static void Main() {
- // Déclaration et initialisation d'une chaîne
- string greeting = "Bonjour, monde !";
-
- // Affichage de la chaîne
- Console.WriteLine(greeting);
-
- // Concaténation de chaînes
- string name = "Josiane";
- string message = greeting + " Je suis " + name + ".";
- Console.WriteLine(message);
-
- // Interpolation de chaînes
- int age = 37;
- string introduction = $"Je m'appelle {name} et j'ai {age} ans.";
- Console.WriteLine(introduction);
-
- // Quelques méthodes utiles sur les chaînes de caractères
- Console.WriteLine($"Longueur de la chaîne : {greeting.Length}");
- Console.WriteLine($"En majuscules : {greeting.ToUpper()}");
- Console.WriteLine($"En minuscules : {greeting.ToLower()}");
- Console.WriteLine($"La chaîne de caractères contient 'monde' : {greeting.Contains("monde")}");
- Console.WriteLine($"Sous-chaîne de caractère (7 à 12) : {greeting.Substring(7, 5)}");
- }
- }
Type de données d'objet
Le type d'objet est un type spécial, étant le parent de tous les autres types dans le cadre d'application .NET. Il peut être déclaré avec mot-clef object et il peut prendre des valeurs de tout autre type. C'est un type de référence, c'est-à-dire un index (adresse) d'une zone mémoire entreposant la valeur actuel.
Voici un exemple d'utilisation d'un type de données d'objet :
- using System;
-
- class Program {
- static void Main() {
- // Déclaration d'un type de données "object"
- object myObject;
-
- // Entreposer un entier dans l'objet
- myObject = 42;
- Console.WriteLine($"Valeur : {myObject}, Type : {myObject.GetType()}");
-
- // Entreposer une chaîne dans le même objet
- myObject = "Bonjour, monde !";
- Console.WriteLine($"Valeur : {myObject}, Type : {myObject.GetType()}");
-
- // Entreposer un objet personnalisé
- myObject = new Person { Name = "Annie", Age = 30 };
- Console.WriteLine($"Valeur : {myObject}, Type : {myObject.GetType()}");
- }
- }
-
- class Person {
- public string Name { get; set; }
- public int Age { get; set; }
-
- public override string ToString() {
- return $"{Name}, {Age} ans";
- }
- }
Les types de données nulles
Les types Nullable sont des enveloppeurs spécifiques autour des types de données de valeur (comme int, double et bool) permettant d'entreposer des données avec une valeur nulle. Il permet aux types de données d'offrir la possibilité d'utiliser l'absence de valeur (c'est-à-dire la valeur nulle) comme types de référence et d'accepter à la fois les valeurs normales et la valeur spéciale null. Ainsi, les types Nullable contiennent une valeur facultative. L'enveloppe d'un type de données spécifié comme Nullable peut être effectué de deux manières :
Les deux déclarations sont équivalentes. Le moyen le plus simple d'effectuer cette opération est d'ajouter un point d'interrogation (?) Après le type, par exemple «int?». Le plus difficile est d'utiliser la syntaxe Nullable <...>. Les types Nullable sont des types de référence, c'est-à-dire qu'ils font référence à un objet dans la mémoire dynamique, contenant leur valeur actuelle. Ils peuvent ou non avoir une valeur et peuvent être utilisés comme types de données primitifs normaux, mais avec quelques spécificités.
Variables
Après avoir passé en revue les principaux types de données en C#, voyons comment nous pouvons les utiliser. Pour travailler avec des données, nous devons utiliser des variables. Nous avons déjà vu leur utilisation dans les exemples, mais examinons-les maintenant plus en détail.
Une variable est un conteneur d'informations, dont la valeur peut changer. Elle permet de :
- entreposer des informations ;
- récupérer les informations entreposées ;
- modifier les informations entreposées.
En programmation C#, vous utiliserez des variables pour entreposer et traiter des informations à tout moment.
Caractéristiques des variables
Les variables sont caractérisées par :
- un nom (identifiant), par exemple l'âge ;
- un type (des informations y étant conservées), par exemple int;
- une valeur (informations entreposées), par exemple 25.
Une variable est une zone nommée de la mémoire, entreposant une valeur d'un type de données particulier, et cette zone de mémoire est accessible dans le programme par son nom. Les variables peuvent être entreposées directement dans la mémoire opérationnelle du programme (dans la pile) ou dans la mémoire dynamique dans laquelle sont entreposés des objets plus volumineux (tels que des chaînes de caractères et des tableaux).
Les types de données primitifs (nombres, char, bool) sont appelés types de valeur car ils entreposent leur valeur directement dans la pile du programme.
Les types de données de référence (tels que les chaînes de caractères, les objets et les tableaux) sont une adresse, pointant vers la mémoire dynamique où leur valeur est entreposée. Ils peuvent être alloués et libérés dynamiquement, c'est-à-dire que leur taille n'est pas fixée à l'avance contrairement au cas des types de valeur.
Nommer des variables - Règles
Lorsque nous voulons que le compilateur alloue une zone mémoire à certaines informations utilisées dans notre programme, nous devons lui donner un nom. Il fonctionne comme un identifiant et permet de faire référence à la zone mémoire concernée.
Le nom de la variable peut être celui de notre choix mais doit suivre certaines règles définies dans la spécification du langage de programmation C# :
- Les noms de variables peuvent contenir les lettres a-z, A-Z, les chiffres 0-9 ainsi que le caractère « _ ».
- Les noms de variables ne peuvent pas commencer par un chiffre.
- Les noms de variables ne peuvent pas coïncider avec un mot-clé du langage C#. Par exemple, base, char, default, int, object, this, null et bien d'autres ne peuvent pas être utilisés comme noms de variables.
Une liste des mots-clefs C# se trouve dans la page Référence de mots réservés (mots clefs). Si nous voulons nommer une variable comme un mot-clef, nous pouvons ajouter un préfixe au nom - « @ ». Par exemple, @char et @null sont des noms de variables valides tandis que char et null ne sont pas valides.
Nommer des variables - Exemples
Noms correctes :
- nom
- premier_Nom
- _nom1
Noms incorrects (conduiront à une erreur de compilation) :
- 1 (chiffre)
- if (mot clef)
- 1name (commence par un chiffre)
Nommer des variables - Recommandations
Nous vous fournirons quelques recommandations sur la façon de nommer vos variables, car tous les noms autorisés par le compilateur ne sont pas appropriés pour les variables :
- Les noms doivent être descriptifs et expliquer à quoi sert la variable. Par exemple, un nom approprié pour une variable entreposant le nom d'une personne est personName et un nom inapproprié est a37.
- Seuls les caractères latins doivent être utilisés. Bien que le compilateur autorise le cyrillique, il n'est pas recommandé de l'utiliser dans les noms de variables ou dans le reste des identifiants du programme.
- En C#, il est généralement accepté que les noms de variables doivent commencer par une petite lettre et inclure des petites lettres, cependant, chaque nouveau mot commence par une majuscule. Par exemple, le nom firstName est correct et mieux à utiliser que firstname ou first_name. L'utilisation du caractère _ dans les noms de variables est considérée comme un mauvais style de nommage.
- Les noms de variables ne doivent être ni trop longs ni trop courts - ils doivent simplement clarifier le but de la variable dans son contexte.
- Les majuscules et les minuscules doivent être utilisées avec précaution car C# les distingue. Par exemple, l'âge et l'âge sont des variables différentes.
Voici quelques exemples de variables bien nommées :
- firstName
- age
- startIndex
- lastNegativeNumberIndex
Et voici quelques exemples de variables mal nommées (bien que les noms soient corrects du point de vue du compilateur C#) :
Nom de variable | Explication |
---|---|
_firstName | Commence par _ |
last_name | Contient _ |
AGE | Est écrit en majuscules |
Start_Index | Commence par une majuscule et contient _ |
lastNegativeNumber_Index | Contient _ |
a37 | Le nom n'est pas descriptif et n'indique pas clairement le but de la variable |
fullName23, fullName24,... | Il n'est pas approprié qu'un nom de variable contienne des chiffres, à moins que cela n'améliore la clarté de la variable utilisée ; si vous devez avoir plusieurs variables avec des noms similaires se terminant par un numéro différent, entreposant le même type de données ou un type similaire, il peut être plus approprié de créer une seule variable de collection ou de tableau et de la nommer fullNamesList, par exemple. |
Les variables doivent avoir des noms expliquant brièvement leur fonction. Lorsqu'une variable est nommée avec un nom inapproprié, cela rend le programme très difficile à lire et à modifier ultérieurement (après un certain temps, lorsque nous avons oublié comment il fonctionne).
Essayez toujours d'utiliser des noms courts et précis lorsque vous nommez les variables. Respectez la règle selon laquelle le nom de la variable doit indiquer à quoi elle sert, par exemple le nom doit répondre à la question «quelle valeur est entreposée dans cette variable». Lorsque cette condition n'est pas remplie, essayez de trouver un meilleur nom. Les chiffres ne sont pas appropriés pour être utilisés dans les noms de variables.
Déclaration de variables
Lorsque vous déclarez une variable, vous effectuez les étapes suivantes :
- spécifiez son type (par exemple int);
- spécifiez son nom (identifiant, par exemple age) ;
- spécifiez éventuellement une valeur initiale (par exemple 25) mais ce n'est pas obligatoire.
La syntaxe de déclaration des variables en C# est la suivante :
type-de-données identificateur [= initialisation]; |
Voici un exemple de déclaration de variables :
Affectation d'une valeur
L'affectation d'une valeur à une variable consiste à fournir une valeur devant être entreposée dans la variable. Cette opération est effectuée par l'opérateur d'affectation «=». Sur le côté gauche de l'opérateur, nous mettons le nom de la variable et sur le côté droit, sa nouvelle valeur.
Voici un exemple d'affectation de valeurs à des variables :
- nom = "Steeve Tremblay";
- age = 25;
Initialisation des variables
En programmation, le terme initialisation signifie spécifier une valeur initiale. Lorsque nous définissons une valeur pour les variables au moment de leur déclaration, nous les initialisons en réalité.
Valeurs par défaut des variables
Chaque type de données en C# possède une valeur par défaut (initialisation par défaut) étant utilisée lorsqu'il n'existe aucune valeur explicitement définie pour une variable donnée. Nous pouvons utiliser le tableau suivant pour voir les valeurs par défaut des types, que nous connaissons déjà :
Type de données | Valeur par défaut |
---|---|
sbyte | 0 |
byte | 0 |
short | 0 |
ushort | 0 |
int | 0 |
uint | 0u |
long | 0L |
ulong | 0u |
float | 0.0f |
double | 0.0d |
decimal | 0.0m |
bool | false |
char | '\u0000' |
string | null |
object | null |
Résumons comment déclarer des variables, les initialiser et leur attribuer des valeurs avec l'exemple suivant :
- // Déclarer et initialiser certaines variables
- byte siecle = 20;
- ushort annees = 2000;
- decimal PIdecimal = 3.141592653589793238m;
- bool estVide = true;
- char caractere = 'a';
- string prenom = "Jean";
- ch = (char)5;
- char deuxiemeCaractere;
- // Ici, nous utilisons une variable déjà initialisée et la réaffectons
- deuxiemeCaractere = ch;
Types de valeur et de référence
Les types de données en C# sont de deux types : valeur et référence.
Les types de valeur sont stockés dans la pile d'exécution du programme et contiennent directement leur valeur. Les types de valeur sont les types numériques primitifs, le type caractère et le type booléen : sbyte, byte, short, ushort, int, long, ulong, float, double, decimal, char, bool. La mémoire leur étant allouée est libérée lorsque le programme sort de leur plage, c'est-à-dire lorsque le bloc de code dans lequel ils sont définis termine son exécution. Par exemple, une variable déclarée dans la méthode Main() du programme est entreposée dans la pile jusqu'à ce que le programme termine l'exécution de cette méthode, c'est-à-dire jusqu'à ce qu'elle se termine (les programmes C# se terminent après avoir entièrement exécuté la méthode Main()).
Les types de référence conservent une référence (adresse), dans la pile d'exécution du programme, et cette référence pointe vers la mémoire dynamique (la mémoire de tas), où leur valeur est entreposée. La référence est un pointeur (adresse de la cellule mémoire) indiquant l'emplacement réel de la valeur dans la mémoire de tas. Un exemple de valeur à l'adresse dans la pile pour l'exécution est 0x00AD4934. La référence a un type. La référence ne peut pointer que vers des objets du même type, c'est-à-dire qu'il s'agit d'un pointeur fortement typé. Tous les types de référence peuvent contenir une valeur nulle. Il s'agit d'une valeur de service spéciale, ce qui signifie qu'il n'y a pas de valeur.
Les types de référence allouent de la mémoire dynamique pour leur création. Ils libèrent également de la mémoire dynamique pour un nettoyage de la mémoire (Ramasse-miettes), lorsqu'elle n'est plus utilisée par le programme. On ne sait pas exactement quand une variable de référence donnée sera libérée du Ramasse-miettes, car cela dépend de la charge de la mémoire et d'autres facteurs. Étant donné que l'allocation et la libération de mémoire sont une opération lente, on peut dire que les types de référence sont plus lents que ceux de valeur.
Comme les types de données de référence sont alloués et libérés de manière dynamique pendant l'exécution du programme, leur taille peut ne pas être connue à l'avance. Par exemple, une variable de type chaîne de caractères peut contenir des données texte dont la longueur varie. En fait, la valeur du texte de la chaîne est entreposée dans la mémoire dynamique et peut occuper un volume différent (nombre d'octets) tandis que la variable de chaîne de caractères entrepose l'adresse de la valeur du texte.
Les types de référence sont toutes les classes, tableaux et interfaces tels que les types : object, string, byte[]. Nous découvrirons les classes, les objets, les strings, les tableaux et les interfaces dans les prochains chapitres de ce livre. Pour l'instant, il suffit de savoir que tous les types, n'étant pas des valeurs, sont des références et que leurs valeurs sont stockées dans la mémoire de tas (la mémoire allouée dynamiquement).
Types de valeur et de référence et mémoire
Dans cet exemple, nous allons illustrer comment les types de valeur et de référence sont représentés en mémoire. Considérons l'exécution du code de programmation suivant :
À ce stade, les variables sont situées dans la mémoire comme suit :
Si nous exécutons maintenant le code suivant, modifiant les valeurs des variables, nous verrons ce qui arrive à la mémoire lors du changement des types de valeur et de référence :
Après ces modifications, les variables et leurs valeurs sont situées dans la mémoire comme suit :
Comme vous pouvez le voir sur la figure, un changement de type de valeur (i = 0) modifie sa valeur directement dans la pile. Lors du changement d'un type de référence, les choses sont différentes : la valeur est modifiée dans le tas (bytes[1] = 0). La variable conservant la référence du tableau reste inchangée (0x00190D12). Lors de l'attribution d'une valeur nulle dans un type de référence, cette référence est déconnectée de sa valeur et la variable reste sans valeur (objet = null).
Lors de l'attribution d'une nouvelle valeur à un objet (une variable de type référence), le nouvel objet est alloué dans la mémoire de tas (la mémoire dynamique) tandis que l'ancien objet reste libre (non référencé). La référence est redirigée vers le nouvel objet (chaine = "Au revoir") tandis que les anciens objets ("Bonjour") seront nettoyés à un moment donné par le Ramasse-miettes (le système interne du .NET pour le nettoyage automatique de la mémoire) car ils ne sont plus utilisés.
Les littéraux
Les types primitifs, que nous avons déjà rencontrés, sont des types de données spéciaux intégrés au langage de programmation C#. Leurs valeurs spécifiées dans le code source du programme sont appelées littéraux. Un exemple permettra de mieux comprendre cela :
Dans l'exemple ci-dessus, les littéraux sont true, «C», 100, 20 000 et 300 000. Ce sont des valeurs variables définies directement dans le code source du programme.
Types de littéraux
En langage de programmation C#, il existe plusieurs types de littéraux :
- Booléen
- Entier
- Réel
- Caractère
- Chaîne de caractères
- Littéral objet null
Littéraux booléens
Les littéraux booléens sont :
- true
- false
Lorsque nous attribuons une valeur à une variable de type bool, nous ne pouvons utiliser qu'une seule de ces deux valeurs ou une expression booléenne (étant calculée à true ou false).
Littéraux booléens - Exemple
Voici un exemple de déclaration d'une variable de type bool et d'attribution d'une valeur, représentant le littéral booléen true :
Littéraux entiers
Les littéraux entiers sont des séquences de chiffres, un signe (+, -), des suffixes et des préfixes. En utilisant des préfixes, nous pouvons présenter des entiers dans la source du programme au format décimal ou hexadécimal. Dans les littéraux entiers, les préfixes et suffixes suivants peuvent faire partie :
- "0x" et "0X" comme préfixe indiquent des valeurs hexadécimales, par exemple 0xA8F1 ;
- 'l' et 'L' comme suffixe indiquent des données de type long, par exemple 357L.
- 'u' et 'U' comme suffixe indiquent le type de données uint ou ulong, par exemple 112u.
Par défaut (si aucun suffixe n'est utilisé), les littéraux entiers sont de type int.
Littéraux entiers - Exemples
Voici quelques exemples d'utilisation de littéraux entiers :
Littéraux réels
Les littéraux réels sont une séquence de chiffres, un signe (+, -), des suffixes et le caractère point décimal. On les utilise pour les valeurs de type float, double et decimal. Les littéraux réels peuvent être représentés au format exponentiel. Ils utilisent également les indications suivantes :
- 'f' et 'F' comme suffixes signifient des données de type float ;
- 'd' et 'D' comme suffixes signifient des données de type double ;
- 'm' et 'm' comme suffixes signifient des données de type decimal ;
- 'e' est un exposant, par exemple, "e-5" signifie la partie entière multipliée par 10-5.
Par défaut (s'il n'y a pas de suffixe), les nombres réels sont de type double.
Littéraux réels - Exemples
Voici quelques exemples d'utilisation de littéraux réels :
Littéraux de caractère
Les littéraux de caractère sont des caractères simples entourés d'apostrophes (guillemets simples). Nous les utilisons pour définir les valeurs de type char. La valeur d'un littéral de caractère peut être :
- un caractère, par exemple 'A';
- un code de caractère, par exemple '\u0065';
- une séquence d'échappement ;
Séquences d'échappement
Il est parfois nécessaire de travailler avec des caractères n'étant pas affichés sur le clavier ou avec des caractères ayant une signification particulière, comme le caractère «nouvelle ligne». Ils ne peuvent pas être représentés directement dans le code source du programme et pour les utiliser, nous avons besoin de techniques spéciales, que nous allons aborder maintenant.
Les séquences d'échappement sont des littéraux. Il s'agit d'une séquence de caractères spéciaux, décrivant un caractère ne pouvant pas être écrit directement dans le code source. Il s'agit par exemple du caractère «nouvelle ligne». Il existe de nombreux exemples de caractères ne pouvant pas être représentés directement dans le code source : un guillemet double, une tabulation, une nouvelle ligne, une barre oblique inverse et d'autres. Voici quelques-unes des séquences d'échappement les plus fréquemment utilisées :
Échappement | Description |
---|---|
\' | Guillemet simple |
\" | Guillemets doubles |
\\ | Barre oblique inverse |
\n | Nouvelle ligne |
\t | Déplacement (tabulation) |
\uXXXX | char spécifié par son numéro Unicode, par exemple \u03A7. |
Le caractère \ (barre oblique inverse) est également appelé caractère d'échappement car il permet l'affichage à l'écran (ou sur un autre périphérique de sortie) de caractères ayant une signification ou un effet particulier et ne pouvant pas être représentés directement dans le code source.
Séquences d'échappement - Exemples
Voici quelques exemples de littéraux de caractères :
- // Un caractère ordinaire
- char caractere = 'a';
- Console.WriteLine(caractere);
- // Code de caractère Unicode au format hexadécimal
- caractere = '\u003A';
- Console.WriteLine(caractere);
- // Affectation du caractère de guillemet simple (échappé par \')
- caractere = '\'';
- Console.WriteLine(caractere);
- // Attribution du caractère barre oblique inverse (échappé par \\)
- caractere = '\\';
- Console.WriteLine(caractere);
Sortie de la console :
a:
'
\
Littéraux de chaîne de caractères
Les littéraux de chaîne de caractères sont utilisés pour les données de type chaîne de caractères. Il s'agit d'une séquence de caractères entourée de guillemets doubles. Toutes les règles d'échappement pour le type char décrites ci-dessus sont également valables pour les littéraux de chaîne de caractères.
Les chaînes de caractères peuvent être précédées du caractère @ qui spécifie une chaîne entre guillemets (chaîne de caractères textuelle). Dans les chaînes de caractères entre guillemets, les règles d'échappement ne sont pas valides, c'est-à-dire que le caractère \ signifie \ et n'est pas un caractère d'échappement. Un seul caractère doit être échappé dans les chaînes entre guillemets - le caractère " (guillemets doubles) et il est échappé de la manière suivante - en le répétant "" (guillemets doubles doubles). Tous les autres caractères sont traités littéralement, même la nouvelle ligne. Les chaînes entre guillemets sont souvent utilisées pour nommer les chemins d'accès au système de fichiers.
Littéraux de chaîne de caractères - Exemples
Voici quelques exemples d'utilisation de littéraux de chaîne de caractères :
Sortie de la console :
"Bonjour, Julie », dit-il.C:\Windows\Notepad.exe
Le \ n'est pas échappé comme \\.
Je suis sur une nouvelle ligne.