• 20 hours
  • Medium

Free online content available in this course.

course.header.alt.is_certifying

Got it!

Last updated on 3/10/17

Gérez votre mémoire et formattez vos données

Log in or subscribe for free to enjoy all this course has to offer!

Dans ce chapitre, vous allez découvrir comment sont gérés les types .NET en mémoire et comment vous allez pouvoir formater vos chaînes de caractères et vos dates. Le framework .NET apporte tout un tas de solutions intéressantes pour maximiser vos solutions de formatage.

Précisions sur les types et gestion mémoire

Nous avons vu beaucoup de types différents au cours des chapitres précédents. Nous avons vu les structures, les classes, les énumérations, les délégués, etc.
Certains sont des types valeur et d’autres des types référence. Et ils sont tous des objets.

Voici un petit schéma récapitulatif des types que nous avons déjà vus :

Répartition des types valeur et référence
Répartition des types valeur et référence

Nous avons dit brièvement que les objets étaient gérés différemment par le framework .NET et que les variables de type valeur contenaient directement la valeur, alors que les variables de type référence possèdent un lien vers un objet en mémoire.
Ce qu’il se passe en fait quand nous déclarons une variable de type valeur, c'est que la machine virtuelle de .NET, de son petit nom CLR (Common Language Runtime), crée directement la valeur en mémoire dans ce qu’on appelle « la pile ».

C’est une zone mémoire (limitée) où il est très rapide de mettre et de chercher des valeurs. De plus, cette mémoire n’a pas besoin d’être libérée par le ramasse-miettes (que nous verrons un peu plus bas). On peut donc être amené à choisir les types valeur lorsque l’on veut améliorer la performance d’une application.

Par exemple, lorsque nous faisons :

int age = 10;
double pourcentage = 5.5;

il se passe ceci en mémoire :

Image utilisateur

La variable age est une adresse mémoire contenant la valeur 10. C’est la même chose pour la variable pourcentage sauf que l’emplacement mémoire est plus important car on peut stocker plus de choses dans un double que dans un int.
En ce qui concerne les types valeur, lorsque nous instancions par exemple une classe, le C# instancie la variable maVoiture dans la pile et lui met dedans une référence vers le vrai objet qui lui est alloué sur une zone mémoire de capacité plus importante, mais à accès plus lent, que l’on appelle « le tas ». Comme il est géré par le framework .NET, on l’appelle « le tas managé ».

Si nous avons le code suivant :

public class Voiture
{
    public int Vitesse { get; set; }
    public string Marque { get; set; }
}

Voiture maVoiture = new Voiture { Vitesse = 10, Marque = "Peugeot" };

Nous aurons en mémoire :

Image utilisateur

À noter que lorsqu’une variable sort de sa portée et qu’elle n’est plus utilisable par qui que ce soit, alors la case mémoire sur la pile est marquée comme de nouveau libre.
Voilà grosso modo comment est gérée la mémoire.

Il manque encore un élément fondamental du mécanisme de gestion mémoire : le ramasse-miettes.
Nous en avons déjà parlé brièvement, le ramasse-miettes sert à libérer la mémoire qui n’est plus utilisée dans le tas managé. Il y aurait de quoi écrire un gros cours rien que sur son fonctionnement, aussi nous allons expliquer rapidement comment il fonctionne sans trop rentrer dans les détails.

Pourquoi libérer la mémoire ?

On a vu que quand une variable sort de portée, alors la case mémoire sur la pile est marquée comme à nouveau libre. C’est très bien avec les types valeur qui sont uniquement sur la pile. Mais avec les types référence ?
Que donne le code suivant lorsque nous quittons la méthode CreerVoiture ?

public class Voiture
{
    public int Vitesse { get; set; }
    public string Marque { get; set; }
}

static void Main(string[] args)
{
    CreerVoiture();
}

public static void CreerVoiture()
{
    Voiture maVoiture = new Voiture { Vitesse = 10, Marque = "Peugeot" };
}

Nous avons dit que la mémoire sur la pile redevenait libre. La référence vers l’objet est donc cassée. Cependant, la mémoire sur le tas est toujours occupée :

Image utilisateur

Cela veut dire que notre objet est toujours en mémoire sauf que la variable maVoiture n’existe plus, et donc ne référence plus cet objet.
Dans un langage comme le C++, nous aurions été obligés de vider explicitement la mémoire référencée par la variable.
En C#, pas besoin ! C’est le ramasse-miettes qui le fait pour nous. Encore un truc de fainéant ça. ^^

En fait, c’est plutôt une sécurité qu’un truc de fainéant. C’est la garantie que la mémoire utilisée par les objets qui n’existent plus est vidée et, du coup, redevient disponible pour de nouveaux objets. Grâce au ramasse-miettes, nous évitons ce que l’on appelle les fuites mémoires.

Super génial ça. Mais, il passe quand ce ramasse-miettes ?

La réponse est simple : « on ne sait pas quand il passe ».
En fait, il passe quand il a besoin de mémoire ou quand l’application semble ne rien faire. Évidemment, lorsque le ramasse-miettes passe, les performances de l’application sont un petit peu pénalisées. C’est pour cela que l’algorithme de passage du ramasse-miettes est optimisé pour essayer de déranger le moins possible l’application, lors des moments d’inactivité par exemple. Par contre, quand il y a besoin de mémoire, il ne se pose pas la question : il passe quand même.

Il y aurait beaucoup de choses à dire encore sur ce mécanisme mais arrêtons-nous là.
Retenons que le ramasse-miettes est un superbe outil qui nous permet de garantir l’intégrité de notre mémoire et qu’il s’efforce au mieux de nous embêter le moins possible. Il est important de libérer les ressources dont on n'a plus besoin quand c’est possible, par exemple en se désabonnant d’un événement ou lorsque nous avons utilisé des ressources natives (ce que nous ne verrons pas dans ce cours) ou lors d’accès à des fichiers ou des bases de données.

La mise en forme et la culture

La mise en forme

Pour l’instant, lorsque nous avons eu besoin de mettre en forme des chaînes de caractères, nous avons utilisé la méthode Console.WriteLine avec en paramètres des chaînes concaténées entre elles grâce à l’opérateur +. Par exemple :

int age = 30;
Console.WriteLine("J'ai " + age + " ans");

Il est important de savoir qu’il est possible de formater la chaîne un peu plus simplement et surtout beaucoup plus efficacement. Ceci est possible grâce à la méthode string.Format. Le code précédent peut par exemple être remplacé par :

int age = 30;
string chaine = string.Format("J'ai {0} ans", age);
Console.WriteLine(chaine);

La méthode string.Format accepte en premier paramètre un format de chaîne. Ici, nous lui indiquons une chaîne de caractères avec au milieu un caractère spécial : {0}. Il permet de dire : « remplace-moi le {0} avec le premier paramètre qui va suivre », en l’occurrence ici la variable age. Si nous avons plusieurs valeurs, il est possible d’utiliser les caractères spéciaux {1}, puis {2}, etc … chaque nombre représentant l’indice correspondant au paramètre. Par exemple :

double valeur1 = 10.5;
double valeur2 = 4.2;
string chaine = string.Format("{0} multiplié par {1} s'écrit \"{0} * {1}\" et donne comme résultat : {2}", valeur1, valeur2, valeur1 * valeur2);
Console.WriteLine(chaine);

Ce qui donne :

10,5 multiplié par 4,2 s'écrit "10,5 * 4,2" et donne comme résultat : 44,1

Vous avez pu remarquer qu’il est possible d’utiliser le même paramètre à plusieurs endroits.
La méthode Console.WriteLine dispose aussi de la capacité de formater des chaînes de caractères. Ce qui veut dire que le code précédent peut s’écrire :

double valeur1 = 10.5;
double valeur2 = 4.2;
Console.WriteLine("{0} multiplié par {1} s'écrit \"{0} * {1}\" et donne comme résultat : {2}", valeur1, valeur2, valeur1 * valeur2);

Ce qui revient absolument au même.

Pour finir sur le formatage des chaînes, il est possible d’utiliser des caractères spéciaux enrichis pour changer le formatage des types numériques ou de la date.

Par exemple, il est possible d’afficher la date sous une forme différente avec :

DateTime date = new DateTime(2011, 12, 25);
Console.WriteLine("La date est {0}", date.ToString("dd-MM-yyyy"));

Ici, dd sert à afficher le jour, MM le mois et yyyy l’année sur quatre chiffre, ce qui donne :

La date est 25-12-2011

Il y a beaucoup d’options différentes que vous pouvez retrouver dans la documentation.

Cela fonctionne de la même façon pour les numériques, qui nous permettent par exemple d’afficher le nombre de différentes façons. Ici par exemple, j’utilise la notation scientifique :

double valeur = 123.45;
Console.WriteLine("Format scientifique : {0:e}", valeur);

Ce qui donne :

Format scientifique : 1,234500e+002

Pour les nombres, il existe différents formatages que l’on peut retrouver dans le tableau ci-dessous :

Format

Description

Remarque

{0:c}

Monnaie

Attention, la console affiche mal le caractère €

{0:d}

Décimal

Ne fonctionne qu’avec les types sans virgules

{0:e}

Notation scientifique

{0:f}

Virgule flottante

{0:g}

Général

Valeur par défaut

{0:n}

Nombre avec formatage pour les milliers

{0:r}

Aller-retour

Permet de garantir que la valeur numérique convertie en chaîne pourra être convertie à nouveau en valeur numérique identique

{0:x}

Héxadécimal

Ne fonctionne qu’avec les types sans virgules

À noter que l’on peut également avoir du formatage grâce à la méthode ToString(). Il suffit de passer le format en paramètres, comme ici où vous pouvez d’afficher uniquement le nombre de chiffres après la virgule qui vous intéressent ou des chiffres significatifs :

double valeur = 10.0 / 3;
Console.WriteLine("Avec 3 chiffres significatifs et 3 chiffres après la virgule : {0}", valeur.ToString("000.###"));

Ce qui donne :

Avec 3 chiffres significatifs et 3 chiffres après la virgule : 003,333

Mettre le format dans la méthode ToString() fonctionne aussi pour la date :

DateTime date = new DateTime(2011, 12, 25);
Console.WriteLine(date.ToString("MMMM"));

Ici, je n’affiche que le nom du mois :

décembre

Voilà pour le formatage des chaînes de caractères.
Lister tous les formatages possibles serait une tâche bien ennuyeuse. Vous aurez l’occasion de rencontrer d’autres formatages qui permettent de faire un peu tout et n’importe quoi. Vous pourrez retrouver la plupart des formatages à partir de ce lien.

La culture

Parlons culture désormais. N’ayez pas peur, rien à voir avec des questions pour des champions, la culture en informatique correspond à tout ce qui a trait aux différences entre les langues et les paramètres locaux. Par exemple, en France nous n'écrivons pas les dates de la même façon qu’aux États-Unis. En France, on écrirait le jour de Noël 2011 de cette façon :

En France

Le 25/12/2011

Alors qu’aux États-Unis, ils l’écriraient :

Aux États-Unis

The 12/25/2011

En inversant donc le mois et le jour.
De la même façon, il existe des différences lorsque nous écrivons les nombres à virgule. En France, on écrirait :

En France

123,45

Alors qu’aux États-Unis, ils l’écriraient :

Aux États-Unis

123.45

Un point à la place d’une virgule, subtile différence.
On a donc souvent des différences entre les langues. Et même plus, on peut avoir des différences entre les langues en fonction de l’endroit où elles sont parlées. Citons par exemple le français de France et le français du Canada.
Il existe donc au sein du système d’exploitation tout une liste de « régions » représentées par un couple de lettres. Par exemple, le français est représenté par les lettres fr. Et même plus précisément, le français de France est représenté par fr-FR alors que celui du Canada est représenté par fr-CA.
C’est ce que l’on retrouve dans les paramètres de notre système d’exploitation lorsqu’on va (sous Windows 7/8) dans le panneau de configuration, « Horloge langue et région » :

Image utilisateur

Puis « Modifier le format de la date, de l’heure ou des nombres ».

Image utilisateur

Vous pouvez choisir le format que vous préférez :

Image utilisateur

Bref, ce choix, vous le retrouvez dans votre application si vous récupérez la culture courante :

Console.WriteLine(System.Threading.Thread.CurrentThread.CurrentCulture);

Avec ceci, nous aurons :

fr-FR

Ce qui est intéressant, c’est que le formatage des chiffres ou des dates change en fonction de la culture. Ainsi, si nous utilisons le français de France, pour le code suivant :

public static void Main(string[] args)
{
    Affiche();
}

public static void Affiche()
{
    Console.WriteLine(System.Threading.Thread.CurrentThread.CurrentCulture);
    decimal dec = 5.5M;
    double dou = 4.8;
    DateTime date = new DateTime(2011, 12, 25);
    Console.WriteLine("Décimal : {0}", dec);
    Console.WriteLine("Double : {0}", dou);
    Console.WriteLine("Date : {0}", date);
}

nous aurons :

fr-FR
Décimal : 5,5
Double : 4,8
Date : 25/12/2011 00:00:00

Il est possible de changer la culture courante de notre application. Si par exemple vous souhaitez qu’elle gère plusieurs cultures, vous pouvez utiliser le code suivant :

System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

Cela indique à votre application que vous souhaitez travailler avec la culture des États-Unis. Ainsi, cet exemple :

public static void Main(string[] args)
{
    System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
    Affiche();
}

public static void Affiche()
{
    Console.WriteLine(System.Threading.Thread.CurrentThread.CurrentCulture);
    decimal dec = 5.5M;
    double dou = 4.8;
    DateTime date = new DateTime(2011, 12, 25);
    Console.WriteLine("Décimal : {0}", dec);
    Console.WriteLine("Double : {0}", dou);
    Console.WriteLine("Date : {0}", date);
}

produira un résultat légèrement différent de ce que nous avions eu un peu plus haut :

en-US
Décimal : 5.5
Double : 4.8
Date : 12/25/2011 12:00:00 AM

Il s’agit exactement de la même information, mais formatée différemment.

À noter qu’il existe encore une autre information de culture, à savoir la langue du système d’exploitation que l’on retrouve dans la culture de l’interface graphique, dans la propriété :

Console.WriteLine(System.Threading.Thread.CurrentThread.CurrentUICulture);

Il s’agit ici de la CurrentUICulture, à ne pas confondre avec la CurrentCulture. Correspondant à la langue du système d’exploitation, nous nous en servirons plus volontiers pour rendre une application multi-langue.

En résumé

  • Le garbage collector est le mécanisme permettant de libérer la mémoire allouée sur le tas managé pour des ressources qui ne sont plus référencées dans une application.

  • Le framework .NET gère les différents formats des chaînes grâce à la culture de l'application.

Example of certificate of achievement
Example of certificate of achievement