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 "surchage" d'une méthode en modifiant uniquement son type de retour.
Dans le présent billet, nous allons continuer d'explorer l'implémentation explicite, à travers un autre de ces cas d'usage : le masquage d'une méthode.
Interface et héritage
En C#, lorsque le développeur définie une classe et qu'il souhaite que celle-ci implémente une interface, il ne peut pas préciser si cette implémentation sera publique, protégée, interne ou privée. Il n'y a pas vraiment de raison technique, mais plutôt des raisons conceptuelles. Les créateurs du langage ont estimé qu'à partir du moment où une classe implémente une interface, cette interface fait partie de l'API publique de la classe.
On peut facilement le voir d'ailleurs. Si vous avez une classe publique qui implémente une interface (par exemple IDisposable), et qu'une méthode sous-jacente n'a pas pas la bonne visibilité (ici, la méthode Dispose n'est pas publique), le compilateur génère une erreur : la méthode ne peut implémenter l'interface car elle n'est pas publique.
Alors, certes, il est vrai que dans la grande majorité des cas, c'est le comportement souhaité. Mais il peut arriver, parfois, qu'une classe ait besoin d'implémenter une interface sans pour autant que les méthodes définies par l'interface fassent partie de l'API publique de la classe. L'exemple sans doute le plus parlant est la définition d'un composant COM.
Les composants COM
Pour rappel, l'aventure des composants COM débuta en 1994, alors que Microsoft recherchait déjà des solutions pour répondre aux problèmes d'interopérabilité entre briques logiciels.
Ce billet n'ayant pas pour objet d'apprendre à définir des composants COM, je redirige les lecteurs intéressés pour approfondir le sujet vers un tutoriel d'Eric METZ ainsi qu'à la documentation officielle sur la MSDN.
Revenons donc à nos moutons.
Ce qu'il faut savoir, c'est que pour pouvoir exposer une API via un composant COM, il est nécessaire de passer par une interface en C#. Et il n'est pas toujours souhaitable que les méthodes spécifiées par cette interface soient directement visibles au niveau de notre classe. Nous pouvons alors utiliser l'implémentation explicite pour parvenir à cela. Le pourquoi il n'est pas toujours souhaitable peut avoir plusieurs réponses.
Le besoin d'avoir un composant COM peut refléter un besoin architecturale interne et n'a pas vocation a être appelé par n'importe qui. On retrouve fréquemment ce cas d'usage dans l'implémentation de .NET Core, où de nombreuses classes implémentent des interfaces de manière explicite afin de "cacher" les méthodes (à noter d'ailleurs que souvent, ces interfaces "privées" ne respectent pas la convention couramment admise et leur nom commence par un autre caractère que la lettre "I". On retrouve des interfaces comme _MemberInfo, _ParameterInfo , etc. qui ont vocation à permettre un accès depuis du code non managé mais pas depuis du code managé (puisque les accès seront autres).
Cela peut aussi s'expliquer par le besoin d'éviter de mélanger 2 API. L'API du composant COM d'un côté, l'API publique "classique" (non COM) de l'autre.
Une autre facette
Mais on peut aussi prendre le problème à l'envers : l'implémentation explicite n'est pas un moyen pour masquer une méthode, mais pour forcer le développeur à utiliser l'interface en lieu et place de l'objet directement.
Ainsi, se crée une indépendance vis-à-vis de l'implémentation. Cela est particulièrement vrai lors du développement d'une couche métier.
Bien évidemment, ce n'est pas obligatoire et tout bon programmeur fera de lui-même cette abstraction. Mais après des heures et des heures de code, il n'est pas impossible que, fatigue aidant, l'attention se relache et que notre programmeur utilise directement l'objet et non via une interface. Alors si on peut l'aider...
Avis personnel : je ne suis pas spécialement pour, mais on trouve ce cas du'utilisation. Pourquoi je ne suis pas pour ? Pour deux raisons.
Tout d'abord, une bonne couche métier ne devrait jamais exposer son implémentation sous-jacente. L'API ne devrait manipuler que des interfaces, que se soit dans les paramètres des méthodes, les valeurs de retour, les propriétés, les événements, etc. Ce qui rend, de facto, l'implémentation explicite inutile dans ce cas.
Ensuite, cela complexifie l'implémentation de la couche métier, où il n'est alors plus possible d'utiliser directement l'API publique sans manipuler un objet par son interface.
Pour une couche métier, je préfère, au niveau de l'implémentation de la classe, de gérer via la visibilité qui a le droit d'accéder ou non aux différentes méthodes.
Le mot de la fin
Je vous ai présenté quelques cas d'utilisation, mais il faut bien l'avouer, nous développons peu, en règle général, de composants COM.
Le masquage pur et simple d'une méthode reste assez rare. Sauf cas particulier, vous n'aurez pas véritablement besoin d'avoir recours à cela.
Le cas présenté dans le billet précédent (masquage pour permettre une spécialisation dans le type de retour) est beaucoup plus classique et utilisé !
Néanmoins, il peut toujours être intéressant d'avoir connaissance de ces cas, pour le jour où...
Découvrir l'implémentation explicite des interfaces en C# (partie 2),
Un tutoriel de François DORIN
Découvrir l'implémentation explicite des interfaces en C# (partie 2),
Un tutoriel de François DORIN
Le , par François DORIN
Une erreur dans cette actualité ? Signalez-nous-la !