Section courante

A propos

Section administrative du site

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 :

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace integersamples
  8. {
  9.     class Program
  10.     {
  11.         static void Main(string[] args)
  12.         {
  13.             byte siecle = 20;
  14.             ushort annees = 2020;
  15.             uint jours = 737300;
  16.             ulong heures = 17695200;
  17.  
  18.             Console.WriteLine("Au " + siecle + " siècle, dans l'année " + annees + ", soit " + jours + " jours, ou " + heures + " heures.");
  19.  
  20.             ulong maxIntValue = UInt64.MaxValue;
  21.             Console.WriteLine(maxIntValue);
  22.         }
  23.     }
  24. }

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 :

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 :

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace RealSamples
  8. {
  9.     class Program
  10.     {
  11.         static void Main(string[] args)
  12.         {
  13.             float floatPI = 3.14159f;
  14.             Console.WriteLine(floatPI); // Nombre 3,14159
  15.             double doublePI = 3.14159;
  16.             Console.WriteLine(doublePI); // 3,14159
  17.             double nan = Double.NaN;
  18.             Console.WriteLine(nan); // NaN
  19.             double infinity = Double.PositiveInfinity;
  20.             Console.WriteLine(infinity); // Infini
  21.         }
  22.     }
  23. }

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 :

  1. using System;
  2.  
  3. class Program {
  4.     static void Main()     {
  5.         // Déclaration des variables
  6.         float floatValue = 1.0f / 3.0f;     // Division avec précision float
  7.         double doubleValue = 1.0 / 3.0;     // Division avec précision double
  8.         decimal decimalValue = 1.0m / 3.0m; // Division avec précision decimal
  9.  
  10.         // Afficher les valeurs
  11.         Console.WriteLine("Précision des types réels en C# :");
  12.         Console.WriteLine($"Valeur float : {floatValue}");   // 7 chiffres significatifs
  13.         Console.WriteLine($"Valeur double : {doubleValue}");  // 15-16 chiffres significatifs
  14.         Console.WriteLine($"Valeur decimal: {decimalValue}"); // 28-29 chiffres significatifs
  15.  
  16.         // Test de sommation pour observer les erreurs d'accumulation
  17.         float floatSum = 0f;
  18.         double doubleSum = 0.0;
  19.         decimal decimalSum = 0.0m;
  20.  
  21.         // Ajouter une petite valeur plusieurs fois
  22.         for (int i = 0; i < 1000000; i++) {
  23.             floatSum += 0.000001f;
  24.             doubleSum += 0.000001;
  25.             decimalSum += 0.000001m;
  26.         }
  27.  
  28.         Console.WriteLine("\nAprès une accumulation répétée (1 000 000 additions) :");
  29.         Console.WriteLine($"Somme float : {floatSum}");   // Erreurs d'arrondi visibles
  30.         Console.WriteLine($"Somme double : {doubleSum}");  // Erreurs d'arrondi minimes
  31.         Console.WriteLine($"Somme decimal: {decimalSum}"); // Aucune erreur d'arrondi
  32.     }
  33. }

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,...

  1. using System;
  2.  
  3. class Program {
  4.     static void Main() {
  5.         // Types réels en C#
  6.         float floatValue = 3.1415927f;     // Précision simple (7 chiffres significatifs)
  7.         double doubleValue = 3.141592653589793;  // Précision double (15-16 chiffres significatifs)
  8.         decimal decimalValue = 3.1415926535897932384626433832m; // Haute précision (28-29 chiffres significatifs)
  9.  
  10.         // Afficher les valeurs
  11.         Console.WriteLine($"Valeur float : {floatValue}");
  12.         Console.WriteLine($"Valeur double : {doubleValue}");
  13.         Console.WriteLine($"Valeur decimal : {decimalValue}");
  14.  
  15.         // Comparaison de précision
  16.         double circleRadius = 1.23456789;
  17.         double circleAreaDouble = Math.PI * Math.Pow(circleRadius, 2); // Utilisation de double
  18.         decimal circleAreaDecimal = (decimal)Math.PI * (decimal)Math.Pow(circleRadius, 2); // Conversion pour decimal
  19.  
  20.         Console.WriteLine($"\nAire d'un cercle avec double : {circleAreaDouble}");
  21.         Console.WriteLine($"Aire d'un cercle avec decimal : {circleAreaDecimal}");
  22.     }
  23. }

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.

  1. using System;
  2.  
  3. class Program {
  4.     static void Main()     {
  5.         // Déclaration et initialisation d'un booléen
  6.         bool isRaining = true;
  7.         bool isSunny = false;
  8.  
  9.         // Afficher les valeurs booléennes
  10.         Console.WriteLine($"Est-ce qu'il pleut ? {isRaining}");
  11.         Console.WriteLine($"Est-ce qu'il fait soleil ? {isSunny}");
  12.  
  13.         // Utilisation dans une condition
  14.         if (isRaining) {
  15.             Console.WriteLine("Prenez un parapluie !");
  16.         } else {
  17.             Console.WriteLine("Pas besoin de parapluie.");
  18.         }
  19.  
  20.         // Combinaison logique
  21.         bool shouldGoOutside = !isRaining && isSunny;
  22.         Console.WriteLine($"Peut-on aller dehors ? {shouldGoOutside}");
  23.  
  24.         // Utilisation avec une expression
  25.         int temperature = 25;
  26.         bool isWarm = temperature > 20;
  27.         Console.WriteLine($"Est-ce qu'il fait chaud ? {isWarm}");
  28.     }
  29. }

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 :

  1. using System;
  2.  
  3. class Program {
  4.     static void Main() {
  5.         // Déclaration et initialisation d'un caractère
  6.         char letter = 'A';
  7.  
  8.         // Afficher le caractère
  9.         Console.WriteLine($"Caractère : {letter}");
  10.  
  11.         // Vérifier si le caractère est une lettre
  12.         bool isLetter = char.IsLetter(letter);
  13.         Console.WriteLine($"Est une lettre ? {isLetter}");
  14.  
  15.         // Vérifier si le caractère est une majuscule
  16.         bool isUpper = char.IsUpper(letter);
  17.         Console.WriteLine($"Est en majuscule ? {isUpper}");
  18.  
  19.         // Convertir en minuscule
  20.         char lower = char.ToLower(letter);
  21.         Console.WriteLine($"En minuscule : {lower}");
  22.  
  23.         // Vérifier si le caractère est un chiffre
  24.         char digit = '5';
  25.         bool isDigit = char.IsDigit(digit);
  26.         Console.WriteLine($"'{digit}' est un chiffre ? {isDigit}");
  27.  
  28.         // Valeur Unicode du caractère
  29.         int unicodeValue = (int)letter;
  30.         Console.WriteLine($"Valeur Unicode de '{letter}' : {unicodeValue}");
  31.     }
  32. }

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# :

  1. using System;
  2.  
  3. class Program {
  4.     static void Main() {
  5.         // Déclaration et initialisation d'une chaîne
  6.         string greeting = "Bonjour";
  7.  
  8.         // Concaténation de chaînes
  9.         string name = "Jinny";
  10.         string message = greeting + ", " + name + "!";
  11.         Console.WriteLine(message); // Affiche : Bonjour, Jinny!
  12.  
  13.         // Longueur de la chaîne
  14.         Console.WriteLine($"La longueur du message est : {message.Length}");
  15.  
  16.         // Accéder à un caractère par son index
  17.         Console.WriteLine($"Premier caractère : {message[0]}");
  18.  
  19.         // Transformation en majuscules
  20.         string uppercaseMessage = message.ToUpper();
  21.         Console.WriteLine($"En majuscules : {uppercaseMessage}");
  22.  
  23.         // Vérifier si une chaîne contient un mot
  24.         bool containsAlice = message.Contains("Jinny");
  25.         Console.WriteLine($"Le message contient 'Jinny' ? {containsAlice}");
  26.  
  27.         // Diviser une chaîne de caractères
  28.         string[] words = message.Split(' ');
  29.         Console.WriteLine("Les mots du message sont :");
  30.         foreach (string word in words) {
  31.             Console.WriteLine(word);
  32.         }
  33.     }
  34. }

Voici un second exemple d'utilisation de string :

  1. using System;
  2.  
  3. class Program {
  4.     static void Main() {
  5.         // Déclaration et initialisation d'une chaîne
  6.         string greeting = "Bonjour, monde !";
  7.  
  8.         // Affichage de la chaîne
  9.         Console.WriteLine(greeting);
  10.  
  11.         // Concaténation de chaînes
  12.         string name = "Josiane";
  13.         string message = greeting + " Je suis " + name + ".";
  14.         Console.WriteLine(message);
  15.  
  16.         // Interpolation de chaînes
  17.         int age = 37;
  18.         string introduction = $"Je m'appelle {name} et j'ai {age} ans.";
  19.         Console.WriteLine(introduction);
  20.  
  21.         // Quelques méthodes utiles sur les chaînes de caractères
  22.         Console.WriteLine($"Longueur de la chaîne : {greeting.Length}");
  23.         Console.WriteLine($"En majuscules : {greeting.ToUpper()}");
  24.         Console.WriteLine($"En minuscules : {greeting.ToLower()}");
  25.         Console.WriteLine($"La chaîne de caractères contient 'monde' : {greeting.Contains("monde")}");
  26.         Console.WriteLine($"Sous-chaîne de caractère (7 à 12) : {greeting.Substring(7, 5)}");
  27.     }
  28. }

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 :

  1. using System;
  2.  
  3. class Program {
  4.     static void Main() {
  5.         // Déclaration d'un type de données "object"
  6.         object myObject;
  7.  
  8.         // Entreposer un entier dans l'objet
  9.         myObject = 42;
  10.         Console.WriteLine($"Valeur : {myObject}, Type : {myObject.GetType()}");
  11.  
  12.         // Entreposer une chaîne dans le même objet
  13.         myObject = "Bonjour, monde !";
  14.         Console.WriteLine($"Valeur : {myObject}, Type : {myObject.GetType()}");
  15.  
  16.         // Entreposer un objet personnalisé
  17.         myObject = new Person { Name = "Annie", Age = 30 };
  18.         Console.WriteLine($"Valeur : {myObject}, Type : {myObject.GetType()}");
  19.     }
  20. }
  21.  
  22. class Person {
  23.     public string Name { get; set; }
  24.     public int Age { get; set; }
  25.  
  26.     public override string ToString()  {
  27.         return $"{Name}, {Age} ans";
  28.     }
  29. }

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 :

  1. Nullable<int> variable1 = null;
  2. int? variable2 = variable1; 

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 :

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 :

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# :

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 :

Noms incorrects (conduiront à une erreur de compilation) :

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 :

Voici quelques exemples de variables bien nommées :

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 :

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 :

  1. string nom;
  2. int age;

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 :

  1. nom = "Steeve Tremblay";
  2. 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 :

  1. // Déclarer et initialiser certaines variables
  2. byte siecle = 20;
  3. ushort annees = 2000;
  4. decimal PIdecimal = 3.141592653589793238m;
  5. bool estVide = true;
  6. char caractere = 'a';
  7. string prenom = "Jean";
  8. ch = (char)5;
  9. char deuxiemeCaractere;
  10. // Ici, nous utilisons une variable déjà initialisée et la réaffectons
  11. 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 :

  1. int i = 42;
  2. char caractere = 'A';
  3. bool resultat = true;
  4. object objet = 42;
  5. string chaine = "Bonjour";
  6. byte[] octets = { 1, 2, 3 };

À 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 :

  1. i = 0;
  2. caractere = 'B';
  3. resultat = true;
  4. objet = null;
  5. chaine = "Au revoir";
  6. octets[1] = 0;

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 :

  1. bool resultat = true;
  2. char majuscule = 'C';
  3. byte b = 100;
  4. short s = 20000;
  5. int i = 300000;     

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 :

Littéraux booléens

Les littéraux booléens sont :

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 :

  1. bool resultat = 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 :

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 :

  1. // Les variables suivantes sont initialisées avec la même valeur
  2. int numberInDec = 16;
  3. int numberInHex = 0x10;
  4. // Cela provoquera une erreur, car la valeur 234L n'est pas int
  5. int longInt = 234L;     

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 :

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 :

  1. // Voici la manière correcte d'attribuer une valeur :
  2. float nombreReel = 12.7f;     
  3.  
  4. // Il s'agit de la même valeur au format exponentiel :
  5. nombreReel = 1.27e+1f;
  6.  
  7. // Ce qui suit provoque une erreur, car 12,7 est le double :
  8. float nombreReel = 12.7;

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 :

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 :

  1. // Un caractère ordinaire
  2. char caractere = 'a';
  3. Console.WriteLine(caractere);
  4. // Code de caractère Unicode au format hexadécimal
  5. caractere = '\u003A';
  6. Console.WriteLine(caractere);
  7. // Affectation du caractère de guillemet simple (échappé par \')
  8. caractere = '\'';
  9. Console.WriteLine(caractere);
  10. // Attribution du caractère barre oblique inverse (échappé par \\)
  11. caractere = '\\';
  12. 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 :

  1. string quotation = "\"Bonjour, Julie », dit-il.";
  2. Console.WriteLine(quotation);
  3. string path = "C:\\Windows\\Notepad.exe";
  4. Console.WriteLine(path);
  5. string verbatim = @"Le \ n'est pas échappé comme \\.
  6. Je suis sur une nouvelle ligne.";
  7. Console.WriteLine(verbatim);

Sortie de la console :

"Bonjour, Julie », dit-il.
C:\Windows\Notepad.exe
Le \ n'est pas échappé comme \\.
Je suis sur une nouvelle ligne.


Dernière mise à jour : Mardi, le 17 novembre 2020