Voir le flux RSS

François DORIN

[Actualité] C# : Implémentation explicite des interfaces - Partie 5

Noter ce billet
par , 11/09/2018 à 22h46 (89 Affichages)
Ce billet s'inscrit dans une série de billets autour de l'implémentation explicite des interfaces en C#.

Dans le premier billet, nous avons vu qu'il existe deux manières d'implémenter une interface en C#. De manière implicite (la voie "classique") et de manière explicite. Le billet était illustré par un exemple d'utilisation, avec la "surcharge" d'une méthode en modifiant uniquement son type de retour.

Dans le second billet, nous avons abordé un autre de ces cas d'usage : le masquage d'une méthode.

Dans le troisième billet, nous avons étudié une autre utilisation possible : implémenter des interfaces définissant les mêmes méthodes, mais avec des sémantiques différentes.

Dans ce quatrième billet, nous avons abordé les propriétés et les événements.

Dans ce 5e billet, qui a priori sera le dernier de la série, nous allons aborder les interactions entre implémentation explicite et polymorphisme.

Nom : logo-csharp.png
Affichages : 1194
Taille : 50,9 Ko

Contexte
Prenons le code suivant, histoire d'illustrer ce billet :
Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System;
 
namespace InstanciationExplicite
{
    public interface IHelloWorld
    {
        void SayHello();
    }
 
    public class Mere : IHelloWorld
    {
        public virtual void SayHello()
        {
            Console.WriteLine("Mère");
        }
    }
 
    public class Fille: Mere, IHelloWorld
    {
        void IHelloWorld.SayHello()
        {
            Console.WriteLine("Fille");
        }
 
    }
 
    public class PetiteFille: Fille
    {
        public override void SayHello()
        {
            Console.WriteLine("Petite fille");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            PetiteFille petiteFille = new PetiteFille();
            Fille fille = petiteFille;
            Mere mere = fille;
            IHelloWorld hello = mere;
 
            petiteFille.SayHello();
            fille.SayHello();
            mere.SayHello();
            hello.SayHello();
        }
    }
}

Rien de bien méchant ici. On définie une interface qui est implémentée par la classe Mere. La classe Fille dérive de la classe Mere, et la classe PetiteFille de la classe Fille.

La classe Mere implémente l'interface IHelloWorld de manière implicite, et définie la méthode SayHello() comme étant virtuelle, afin de pouvoir la redéfinir au niveau des classes filles.

Notez également que la classe Fille implémente l'interface IHelloWorld de manière explicite.

Et maintenant, regardons ce que nous obtenons lorsque nous appelons la méthode SayHello().

Résultats
Essayer de deviner la sortie n'est pas forcément très trivial.
Petite fille
Petite fille
Petite fille
Fille
Les 3ères lignes ne présentent aucune surprise. Passons à la 4e. Contre toute attente, la valeur affichée est "Fille" et non "Petite fille" malgré le fait que la variable hello contienne une instance de la classe PetiteFille. Ici, nous constatons donc que l'implémentation explicite prime sur le polymorphisme ! Ainsi, la présence d'une implémentation explicite (et ce quel que soit le niveau dans la chaîne d'héritage) vient masquer le polymorphisme.

Et le pire dans tout cela, c'est qu'il n'y a aucun moyen de préciser le comportement souhaité.

Conclusion
Ainsi, nous constatons que l'instanciation explicite casse le polymorphisme, et surtout, qu'il est impossible d'empêcher cela. Il faut donc faire attention à ne pas se retrouver dans cette situation, au risque d'avoir des comportements contre intuitifs.

Envoyer le billet « C# : Implémentation explicite des interfaces - Partie 5 » dans le blog Viadeo Envoyer le billet « C# : Implémentation explicite des interfaces - Partie 5 » dans le blog Twitter Envoyer le billet « C# : Implémentation explicite des interfaces - Partie 5 » dans le blog Google Envoyer le billet « C# : Implémentation explicite des interfaces - Partie 5 » dans le blog Facebook Envoyer le billet « C# : Implémentation explicite des interfaces - Partie 5 » dans le blog Digg Envoyer le billet « C# : Implémentation explicite des interfaces - Partie 5 » dans le blog Delicious Envoyer le billet « C# : Implémentation explicite des interfaces - Partie 5 » dans le blog MySpace Envoyer le billet « C# : Implémentation explicite des interfaces - Partie 5 » dans le blog Yahoo

Catégories
DotNET , C#

Commentaires

  1. Avatar de tomlev
    • |
    • permalink
    Intéressant! Mais tu décris ce comportement comme un problème, alors que finalement il me semble assez logique, et peut parfois être utile. Par exemple si tu dois hériter d'une classe C qui implémente une interface I, et tu voudrais overrider la méthode M mais elle n'est pas virtuelle : tu peux quand même t'en sortir en implémentant l'interface explicitement.
  2. Avatar de François DORIN
    • |
    • permalink
    Je le présente comme un problème car cela "casse" le polymorphisme classique. Mais on peut effectivement, avec ce que tu viens justement de souligner, créer un polymorphisme directement au niveau des interfaces.

    Maintenant, c'est un soucis car il n'est pas possible de préciser le comportement souhaité. Par exemple, si on surcharge une méthode virtuelle, on peut utiliser soit new, soit override pour préciser si l'on souhaite réimplémenter une méthode, ou si on souhaite "masquer" la méthode de la classe parente. Chose impossible ici malheureusement.