Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Méthodes d’extension : le piège à connaître

[new:30/03/2014]Hier je vous parlais des méthodes d'extension en rappelant leur utilité en C#. Un lecteur très attentif m'a fait remarquer l'existence d'un piège que je n'évoquais pas…

Mitsu, le retour

Oui, c'est bien de notre Mitsu national dont je parle, l'idole des jeunes et même des moins jeunes d'ailleurs. Qui même s'il ne fait plus partie des employés de MS France sait toujours aussi bien magner le clavier et qui a su garder l'œil vif du spécialiste de C# !

Or Mitsu m'a fait remarquer que les méthodes d'extensions avaient une particularité que je n'avais pas mentionnée. Honte sur moi, il l'avait écrit dans un billet que je me rappelle avoir lu maintenant qu'on en parle !

Certes ce billet date de juillet 2007… mais son contenu est toujours vrai et c'est donc un plaisir et un honneur que de rappeler l'existence de celui-ci ainsi que des archives du blog de Mitsu qui contiennent toujours des pépites dont je vous conseille la lecture (http://blogs.msdn.com/b/mitsufu/).

La résolution du nom

Tout le problème est là. Résoudre le nom d'une méthode d'extension. Le compilateur s'en charge certes, mais comment ?

Puisque les méthodes d'extensions sont des « pièces rapportées » qui viennent étendre la partie publique d'une classe et puisqu'elles peuvent être déclarées où on le veut et qu'il peut y avoir plusieurs méthodes d'extensions pour un même type forcément il peut y avoir des conflits.

Il faut donc dans un premier temps rester vigilant sur la possibilité de conflit entre méthodes d'extensions.

Vigilant comment ?

…Très !

Car les méthodes d'extension peuvent aussi étendre plusieurs types appartenant à une même hiérarchie de classes et là ça se complique un peu.

Comment le compilateur résout-il le nom des ME ? … Dans la portée courante.

Ce qui implique que si dans cette portée plusieurs ME de même signature visent le même type il y aura un conflit évident que le compilateur signalera par une erreur de compilation. Ici c'est donc facile, C# prévient que le développeur a fait une boulette…

Là où ça se corse, c'est si plusieurs solutions sont trouvées pour différents types dans une même hiérarchie… C# décidera de la ME à utiliser en fonction du type de la référence et non de celui de l'instance !!!

Référence et non instance, le gros piège…

C'est un piège car ce doit être le seul endroit dans C# où un tel choix est fait le compilateur. Partout ailleurs c'est le type de l'instance qui sert à trancher sur le choix éventuel que le compilateur doit faire.

Donc dans cet unique cas des Méthodes d'Extension C# va utiliser le type de la référence pour choisir la ME à appeler et non pas celui de l'instance manipulée.

Cela peut être extrêmement troublant comme on se l'imagine… maintenant que j'en parle. Enfin maintenant que Mitsu m'a fait remarquer qu'il serait intéressant d'en (re)parler !

Et combien a-t-il raison !

Prenons d'ailleurs directement à la source l'exemple que Mitsu utilisait :

public class A { }

 

public class B : A { }

 

public static class MyExtensions

{

//Etend la classe A

public static void Test(this A a) { ... }

public static void Test(this B b) { ... }

}

 

Avec ce code en tête regardons ces appels de ME :

B b = new B();
b.Test();

Ici pas de problème l'instance est de type B et la référence sur l'instance l'est aussi. Donc la ME « Test() » qui sera appelée sera bien celle auquel on s'attend, la seconde de l'exemple ci-dessus qui étend le type B.

A a = b;
a.Test();

A la suite du code précédent tapons celui qui se trouve ci-dessus. On crée une variable de type A à laquelle nous assignons l'instance de B créée plus haut. Rien de plus naturel en programmation objet… A étant la classe mère, elle peut pointer tout enfant de la hiérarchie qu'elle génère.

Seulement quand la méthode « Test() » est appelée juste après l'assignation, et bien que le type de l'instance manipulée soit B, c'est la ME qui étend le type A qui sera appelée par le compilateur !

Cela doit forcer à la réflexion, et comme me le faisait remarquer Mitsu, connaître ce piège et en comprendre les implications c'est un peu ce qui fait la différence entre simple utilisateur de ME déjà écrites et développeur capable d'écrire des ME …

Conclusion

C# est un langage merveilleux, il a su s'enrichir comme aucun autre en proposant des extensions d'une puissance extraordinaire sans rien casser de sa logique. Malgré tout ce haut degré de sophistication cache quelques pièges qu'il est bon de connaître…

Retrouver le Quizz original de Mitsu : http://blogs.msdn.com/b/mitsufu/archive/2007/07/23/geek-quizz.aspx

Car même si vous avez compris ce qui précède, répondre à la question du Quizz n'est pas si facile ! Recherchez aussi sur son blog d'autres Quizz, notamment ceux sur Linq m'ont laissé un souvenir impérissable, prise de tête garantie !

Qu'il est bon de se coucher moins bête que la veille n'est-ce pas ? J

Merci Mitsu !

Stay Tuned !

blog comments powered by Disqus