DY

DelahayeYourself

modules / M2104 /

TP09: Surcharge

Surchage de l'affichage

Nous avons depuis le début de notre aventure utilisé la méthode Console.WriteLine pour afficher des informations dans la console. Toutefois il s'agissait d'afficher directement des chaines de caractères ou des types scalaires. Que se passe t'il si nous passons un type non-scalaire à cette méthode ?

Exemple n°1

Au sein du Main de votre classe Program de votre solution MesozoicSolution ajouter le code suivant:

Dinosaur dinosaur = new Stegausaurus("Louis", 12);
Console.WriteLine(dinosaur);
  1. Que se passe t'il si l'on exécute notre programme ?
  2. Comprenez-vous ce qui est affiché ?
La classe Object

Comme nous l'avons vu en cours, tout nos classes héritent automatiquement de la classe Object.

Ainsi ce schéma UML:

UML class diagram
Diagramme UML

est équivalent à celui-ci:

UML class diagram
Diagramme UML

Par convention on ne fait pas figurer sur un diagramme de classe l'héritage par défaut de la classe object étant donné que celui-ci est implicite.

La méthode ToString

La classe object fournit une méthode ToString qui retourne une chaîne qui représente l'objet actuel.

Ainsi ce code:

Dinosaur dinosaur = new Stegausaurus("Louis", 12);
Console.WriteLine(dinosaur);

est équivalent à celui-ci:

Dinosaur dinosaur = new Stegausaurus("Louis", 12);
Console.WriteLine(dinosaur.ToString());

ou encore à celui-ci:

Dinosaur dinosaur = new Stegausaurus("Louis", 12);
string dinosaur_repr = dinosaur.ToString();
Console.WriteLine(dinosaur_repr);

Cette méthode est bien évidemment surchargeable pour l'adapter à nos besoins:

public class Stegausaurus
{
    public override string ToString()
    {
        // We only call base ToString from Object class Here
        return base.ToString();
    }
}
A vous de jouer

Nous allons implémenter une surchage de la méthode ToString au sein de la classe (abstraite) Dinosaur de sorte à obtenir ceci:

Dinosaur dinosaur = new Stegausaurus("Louis", 12);
Console.WriteLine(dinosaur); // Mesozoic.Stegausaurus = {name: Louis, age: 12}
  1. Créez les T.Us correspondant à notre besoin,
  2. Implémentez la méthode et vérifiez son fonctionnement.

Surcharge d'opérateur

Exemple n°2

Au sein du Main de votre classe Program de votre solution MesozoicSolution ajouter le code suivant:

Dinosaur louis = new Stegausaurus("Louis", 12);
Dinosaur louis2 = new Stegausaurus("Louis", 12);
//Console.WriteLine(dinosaur);
Console.WriteLine(louis == louis2);
louis2 = louis;
Console.WriteLine(louis == louis);
  1. Que se passe t'il si l'on exécute notre programme ?
  2. Comprenez-vous pourquoi ?
La méthode Equals

La classe object fournit une méthode Equals qui détermine si deux instances d'objets sont égales.

Ainsi ce code:

Dinosaur dinosaur = new Stegausaurus("Louis", 12);
Dinosaur dinosaur2 = new Stegausaurus("Louis", 12);
Console.WriteLine(dinosaur == dinosaur2);

est équivalent à celui-ci:

Dinosaur dinosaur = new Stegausaurus("Louis", 12);
Dinosaur dinosaur2 = new Stegausaurus("Louis", 12);
Console.WriteLine(dinosaur.Equals(dinosaur2));
HashCode

La méthode GetHashCode fait office de fonction de hachage par défaut. C'est à dire qu'elle fournit pour un objet un code numérique unique créer à partir de ses attributs.

Voici un exemple de création d'un Hash pour une classe, le hash est une agrégation des hash des différents attribut de l'objet.

public class Dinosaur
{
    public override int GetHashCode()
    {
        int hash = 13;
        hash ^= this.name.GetHashCode();
        hash ^= this.age.GetHashCode();
        hash ^= this.Specie.GetHashCode();
        return hash;
    }
}

Cette méthode doit être implémenter pour permettre la comparaison d'objet, ainsi deux objets ayant les mêmes valeurs d'attributs retourneront le même hash.

Dinosaur louis = new Stegausaurus("Louis", 12);
Dinosaur louis2 = new Stegausaurus("Louis", 12);
Dinosaur nessie = new Diplodocus("Nessie", 11);

Console.WriteLine(louis.GetHashCode()); // 2034845202
Console.WriteLine(louis2.GetHashCode()); //2034845202
Console.WriteLine(nessie.GetHashCode()); //-275418933

On peut donc comparer la valeur des hash, toutefois il est possible de faire mieux avec la surcharge d'opérateur.

Surcharge d'opérateur(s)

La surchage d'opérateur en c# permet de préciser un comportement sur la comparaison entre deux instances. Ainsi il est possible d'implémenter un comportement spécifique pour l'opérateur d'égalité (==) entre deux instances d'une même classe. Il faudra également implémenter l'inverse de l'opérateur d'égalité .. la différence (!=).

L'opérateur d'égalité compare chaque attribut des objets pour valider leurs égalités. La différence fait l'inverse.

public class Dinosaur
{
    public static bool operator ==(Dinosaur dino1, Dinosaur dino2)
    {
        return dino1.name == dino2.name && dino1.Specie == dino2.Specie && dino1.age == dino2.age;
    }

    public static bool operator !=(Dinosaur dino1, Dinosaur dino2)
    {
        return !(dino1 == dino2);
    }
}
Implémentation de la méthode Equals

Enfin il est possible d'implémenter la méthode Equals en ce basant sur l'opérateur d'égalité. Remarquez l'introduction du mot clé is qui valide le type d'un objet.

public class Dinosaur {

    public override bool Equals(object obj)
    {
        return obj is Dinosaur && this == (Dinosaur)obj;

    }
}
A vous de jouer

Nous allons implémenter une surchage de la méthode Equals et de l'opérateur d'égalité au sein de la classe (abstraite) Dinosaur de sorte à obtenir ceci:

Dinosaur dinosaur = new Stegausaurus("Louis", 12);
Stegausaurus dinosaur2 = new Stegausaurus("Louis", 12);
Dinosaur dinosaur3 = new Diplodocus("Louis", 12);
Console.WriteLine(dinosaur == dinosaur2); // True
Console.WriteLine(dinosaur == dinosaur3); // False
  1. Créez les T.Us correspondant à notre besoin,
  2. Implémentez les méthode(s) et vérifiez leurs fonctionnements.