par , 16/08/2018 à 22h25 (6789 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 ce troisième billet, nous allons étudier une autre utilisation possible : implémenter des interfaces définissant les mêmes méthodes, mais avec des sémantiques différentes.
Multiples interfaces... une méthode
Que se passe-t-il si une classe doit implémenter deux interfaces qui définissent la même méthode ?
Prenons l'exemple suivant :
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
| public interface ITemperatureCelsius
{
float GetTemperature();
}
public interface ITemperatureKelvin
{
float GetTemperature();
}
public interface ITemperatureFarhenheit
{
float GetTemperature();
}
public class Temperature : ITemperatureCelsius, ITemperatureKelvin, ITemperatureFarhenheit
{
private float _temperature;
public Temperature(float temperature)
{
_temperature= temperature;
}
public float GetTemperature()
{
return _temperature;
}
} |
Ce code compile correctement, mais est-il correct pour autant ? La réponse est non.
Non, car si la classe implémente bien les différentes interfaces, on constate que la même implémentation implicite est partagée par les 3 interfaces. Pourtant, nous savons bien qu'une température en degré Celsius, degré Kelvin ou degré Farenheit, même si elles sont liées, ne sont pas égales.
Comment faire donc pour résoudre ce cas ? Utilisons l'implémentation explicite des interfaces !
Rappel métrologique
Sans rentrer dans les détails (les pages Wikipédia consacré au degré Farhenheit et degré Kelvin feront très bien l'affaire), je rappelle juste ici les formules qui nous seront utiles pour la suite du billet :
- Celsius vers Farhenheit :
![Formule mathématique Formule mathématique](http://miscws.developpez.com/latex2pngcache.php?latex=C4l3U7BVCIl3VogpycxNLVYw1LNQ0FYwNgIA)
- Farhenheit vers Celsius :
![Formule mathématique Formule mathématique](http://miscws.developpez.com/latex2pngcache.php?latex=C4l3VrBViEkrSkyuDol3U9BVMDaqrTbUs6gFAA)
- Celsius vers Kelvin :
![Formule mathématique Formule mathématique](http://miscws.developpez.com/latex2pngcache.php?latex=C4n3VrBVCIl3VtBVMDI31jM0BQA)
- Kelvin vers Celsius :
![Formule mathématique Formule mathématique](http://miscws.developpez.com/latex2pngcache.php?latex=C4l3VrBVCIn3VtBWMDI31jM0BQA)
Implémentation explicite à la rescousse
Utilisons l'implémentation explicite pour implémenter chacune des interfaces. Au passage, rendons le constructeur privé, et définissons des méthodes statiques pour instancier des températures en utilisant le référentiel souhaité.
Nous obtenons donc :
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
| public class Temperature : ITemperatureCelsius, ITemperatureKelvin, ITemperatureFarenheit
{
private float _temperature; // La température est stockée en Celsius
private Temperature(float temperature)
{
_temperature = temperature;
}
public static FromCelsius(float celsius)
{
return new Temperature(celsius);
}
public static FromKelvin(float kelvin)
{
return new Temperature(kelvin + 273.15);
}
public static FromFarhenheit(float farhenheit)
{
return new Temperature((farhenheit - 32) / 1.8);
}
float ITemperatureCelsius.GetTemperature()
{
return _temperature;
}
float ITemperatureKelvin.GetTemperature()
{
return _temperature - 273.15;
}
float ITemperatureFehrenheit.GetTemperature()
{
return _temperature * 1.8 + 32;
}
} |
Nous avons ainsi défini une classe permettant de faire facilement des conversions de température.
Son utilisation est des plus simples :
1 2 3 4
| Temperature t = Temperature.FromCelsius(25);
float t_C = (t as ITemperatureCelsius).GetTemperature();
float t_K = (t as ITemperatureKelvin).GetTemperature();
float t_F = (t as ITemperatureFahrenheit).GetTemperature(); |
Conclusions
Nous venons de voir un cas d'usage supplémentaire de l'instanciation explicite : le cas où plusieurs interfaces définissent la même méthode.
Il y a de nombreuses situations où cela peut servir. Dans un cas de conversion d'unité par exemple (comme l'exemple ci-dessus). Mais il peut arriver également que deux interfaces définissent la même méthode avec une sémantique totalement différente. L'instanciation explicite nous permet alors de répondre à cette problématique.