• 20 hours
  • Medium

Free online content available in this course.

course.header.alt.is_certifying

Got it!

Last updated on 3/10/17

Les structures

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

Nous allons aborder dans ce chapitre les structures qui sont une nouvelle sorte d’objets que nous pouvons créer dans des applications C#.
Les structures sont presque comme des classes. Elles permettent également de créer des objets, possèdent des variables ou propriétés, des méthodes et même un constructeur, mais avec quelques subtiles différences …

Découvrons les dès à présent.

Une structure est presque une classe

Une des premières différences est la façon dont .NET gère ces deux objets. Nous avons vu que les classes étaient des types référence. Les variables de type référence ne possèdent donc pas la valeur de l’objet mais une référence vers cet objet en mémoire. La structure quant à elle est un type valeur et contient donc directement la valeur de l’objet.

Une autre différence est que la structure, bien qu’étant un objet, ne peut pas utiliser les principes d’héritage. On ne peut donc pas hériter d’une structure et une structure ne peut pas hériter des comportements d’un objet.

À quoi sert une structure ?

Les structures vont être utiles pour stocker des petits objets qui vont avoir tendance à être souvent manipulés, comme les int ou les bool que nous avons déjà vus.

La raison tient dans un seul mot : performance.

Étant gérées en mémoire différemment, les structures sont optimisées pour améliorer les performances des petits objets. Comme il n’y a pas de référence, on utilisera directement l’objet sans aller le chercher via sa référence. On gagne donc un peu de temps lorsqu’on a besoin de manipuler ces données.
C’est tout à fait pertinent pour des programmes où la vitesse est déterminante, comme les jeux vidéo.

Donc dans ce cas, autant utiliser tout le temps des structures, non ?

Eh bien non, déjà vous vous priveriez de tous les mécanismes d’héritage que nous avons vus. Ensuite, si nous surchargeons trop la mémoire avec des structures, l’optimisation prévue par .NET risque de se retourner contre nous et notre application pourrait être plus lente que si nous avions utilisé des classes.

D’une manière générale, et à moins de savoir exactement ce que vous faites ou d’avoir mesuré les performances, vous allez utiliser plus généralement les classes que les structures.
Vous pouvez à ce sujet aller lire les recommandations de Microsoft.

Créer une structure

Pour créer une structure, nous utiliserons le mot-clé struct, comme nous avions utilisé le mot-clé class pour créer une classe :

public struct Personne
{
    public string Prenom { get; set; }
    public int Age { get; set; }
}

Pour instancier cette structure, nous pourrons utiliser le mot-clé new, comme pour les classes. La différence est que la variable sera un type valeur, avec les conséquences que ce type impose en matière de gestion en mémoire ou de passages par paramètres :

Personne nicolas = new Personne() { Prenom = "Nicolas", Age = 30 };
Console.WriteLine(nicolas.Prenom + " a " + nicolas.Age + " ans");

Comme nous avons dit, il est impossible qu’une structure hérite d’une autre structure ou d’un objet. Sauf bien sûr du fameux type de base object, pour qui c’est automatique. Une structure hérite donc des quelques méthodes d’Object (comme ToString()) que nous pouvons éventuellement spécialiser :

public struct Personne
{
    public string Prenom { get; set; }
    public int Age { get; set; }

    public override string ToString()
    {
        return Prenom + " a " + Age + " ans";
    }
}

Et nous pourrons avoir :

Personne nicolas = new Personne() { Prenom = "Nicolas", Age = 30 };
Console.WriteLine(nicolas.ToString());

Qui renverra :

Nicolas a 30 ans

Comme pour les classes, il est possible d’avoir des constructeurs sur une structure à l’exception du constructeur par défaut qui est interdit.

Aussi le code suivant :

public struct Personne
{
    public Personne()
    {
    }
}

provoquera l’erreur de compilation suivante :

Les structures ne peuvent pas contenir de constructeurs exempts de paramètres explicites

Par contre, les autres formes des constructeurs sont possibles, comme :

public struct Personne
{
    private int age;
    public Personne(int agePersonne)
    {
        age = agePersonne;
    }
}

Qui s’utilisera comme pour une classe :

Personne nicolas = new Personne(30);

Attention, si vous tentez d’utiliser des propriétés ou des méthodes dans le constructeur d’une structure, vous allez avoir un problème.
Par exemple le code suivant :

public struct Personne
{
    private int age;
    public Personne(int agePersonne)
    {
        AffecteAge(agePersonne);
    }

    private void AffecteAge(int agePersonne)
    {
        age = agePersonne;
    }
}

provoquera les erreurs de compilation suivantes :

L'objet 'this' ne peut pas être utilisé avant que tous ses champs soient assignés

Le champ 'MaPremiereApplication.Personne.age' doit être totalement assigné avant que le contrôle soit retourné à l'appelant

Alors qu’avec une classe, ce code serait tout à fait correct.
Pour corriger ceci, il faut absolument initialiser tous les champs avant de faire quoi que ce soit avec l’objet, comme l’indique l’erreur.

Nous pourrons par exemple faire :

public struct Personne
{
    private int age;
    public Personne(int agePersonne)
    {
        age = 0;
        AffecteAge(agePersonne);
    }

    private void AffecteAge(int agePersonne)
    {
        age = agePersonne;
    }
}

Ce qui peut sembler tout à fait inutile dans ce cas-là. Mais comme le compilateur fait certaines vérifications, il sera impossible de compiler un code de ce genre sans que toutes les variables soient initialisées explicitement.

Par contre, vous aurez un souci si vous utilisez des propriétés automatiques. Si nous tentons de faire :

public struct Personne
{
    public int Age { get; set; }
    public Personne(int agePersonne)
    {
        Age = agePersonne;
    }
}

nous nous retrouverons avec la même erreur de compilation.
Pour la corriger, il faudra appeler le constructeur par défaut de la structure qui va permettre d’initialiser toutes les variables de la classe :

public struct Personne
{
    public int Age { get; set; }
    public Personne(int agePersonne) : this()
    {
        Age = agePersonne;
    }
}

Cela se fait comme pour les classes, en utilisant le mot-clé this suivi de parenthèses qui permettront d’appeler le constructeur par défaut.

Rappelez-vous que le constructeur par défaut s’occupe d’initialiser toutes les variables d’une classe ou d’une structure.

Passage de structures en paramètres

Comme il s’agit d’un type valeur, à chaque fois que nous passerons une structure en paramètres d’une méthode, une copie de l’objet sera faite.
Ainsi, tout à fait logiquement, le code suivant :

static void Main(string[] args)
{
    Personne nicolas = new Personne() { Age = 30 };
    FaitVieillir(nicolas);
    Console.WriteLine(nicolas.Age);
}

private static void FaitVieillir(Personne personne)
{
    personne.Age++;
}

affichera 30 bien que nous modifions l’âge de la personne dans la méthode.

Comme nous l’avons déjà vu, la méthode travaille sur une copie de la structure.
Cela veut bien sûr dire que si nous souhaitons modifier une structure à partir d’une méthode, nous devrons utiliser le mot-clé ref :

static void Main(string[] args)
{
    Personne nicolas = new Personne() { Age = 30 };
    FaitVieillir(ref nicolas);
    Console.WriteLine(nicolas.Age);
}

private static void FaitVieillir(ref Personne personne)
{
    personne.Age++;
}

Cela vaut pour tous les types valeur.

Prenez quand même garde. Si la structure est très grosse, le fait d’en faire une copie à chaque utilisation de méthode risque d’être particulièrement chronophage et pourra perturber les performances de votre application.

D’autres structures ?

Vous l’aurez peut-être deviné, mais les entiers que nous avons déjà vus et que nous utilisions grâce au mot-clé int sont en fait des structures.

Étant très souvent utilisés et n’ayant pas non plus énormément de choses à stocker, ils sont créés en tant que structures et sont optimisés par .NET pour que nos applications s’exécutent de façon optimale. Ce qui est un choix tout à fait pertinent.
C'est le cas également pour les bool, les double, etc ...

Toutefois, d’autres objets, comme la classe String, sont bel et bien des classes.

D’une manière générale, vous allez créer peu de structures en tant que débutant. Il sera plus judicieux de créer des classes dès que vous en avez besoin. En effet, plus vos objets sont gros et plus ils auront intérêt à être des classes pour éviter d’être recopiés à chaque utilisation.
L’utilisation de structures pourra se révéler pertinente dans des situations bien précises, mais en général, il faut bien maitriser les rouages du framework .NET pour que les bénéfices de leurs utilisations se fassent ressentir.

Dans tous les cas, il sera important de mesurer (avec par exemple des outils de profilage) le gain de temps avant de mettre des structures partout.

En résumé
  • Les structures sont des types valeur qui sont optimisés par le framework .NET.

  • Une structure est un objet qui ressemble beaucoup à une classe, mais qui possède des restrictions.

  • Les structures possèdent des propriétés, des méthodes, des constructeurs, etc.

  • Il n'est pas possible d'utiliser l'héritage avec les structures.

Example of certificate of achievement
Example of certificate of achievement