cs_GRenard
Messages postés1662Date d'inscriptionlundi 16 septembre 2002StatutMembreDernière intervention30 juillet 2008
-
5 mai 2008 à 17:26
cs_GRenard
Messages postés1662Date d'inscriptionlundi 16 septembre 2002StatutMembreDernière intervention30 juillet 2008
-
7 mai 2008 à 08:44
En PHP et en C++, il est possible de choisir à quelle classe on veut parler directement lors d'un polymorphisme
this. remonte à l'enfant
parent:: remonte au parent
NameOfYourClass:: appelle directement la classe en question
Alors voici l'exemple
j'ai
A -> B -> C
A étant une classe mère abstraite
B étant la fille de A et abstratite
C étant la fille de B et NON abstraite
Chacun implémente la méthode "calculate()" avec "virtual" et "override"
J'instancie C
dans une fonction de B j'appelle ceci :
private void something() {
this.calculate(); // Will call C
base.calculate(); // Will call A
// Comment appeler B.calculate() ?
}
Comme je disais, en PHP je ferais : B::calculate(), même chose en C++... Alors en C# ?
J'ai joué avec les virtual, override et new keyword pour les méthodes, mais je ne veux pas perdre mon principe de polymorphisme avec mon this, je veux seulement appeler ma méthode sur B directement dans ce cas ci.
jesusonline
Messages postés6814Date d'inscriptiondimanche 15 décembre 2002StatutMembreDernière intervention13 octobre 201029 5 mai 2008 à 17:59
[Je redirige vers csharpfr.com tu auras surement plus de retour]
Conceptuellement parlant je trouve ca "choquant" de faire un A::calculate() dans C, dans ce cas l'héritage n'a pas vraiment de sens puisqu'il y aurait un saut d'héritage.
Dans ton exemple base.calculate() n'est pas équivalent à A::calculate() mais plutot à B::calculate(), le mot clé base se refere à la classe parente et pas la classe orginal (sauf si évidement la méthode calculate n'est pas surchargé dans B ce qui n'est pas le cas).
En tout cas, je ne connais pas de façon de faire ce que tu demandes en C# (à part utiliser la reflection ce qui est beurk). Mais je ne pense pas que ca manque en C#, au contraire même ...
cs_GRenard
Messages postés1662Date d'inscriptionlundi 16 septembre 2002StatutMembreDernière intervention30 juillet 20081 5 mai 2008 à 20:05
Voici un morceau de code
Si vous ne savez pas, ne répondez pas "pense ton code différemment". Je sais très bien que si ne ne trouve pas de solution, je vais prendre cette option.
// A public virtual int calculate(){
int val = 10;
return val;
}
protected abstract void doSomething();
// B
public override int calculate() {
int val = base.calculate();
val += 2;
return val;
}
protected override void doSomething() {
// ICI
$valTotal = $this.calculate(); // 5+2+10
// Je souhaite avoir seulement 12 (10+2)
// $valHere = B.calculate();
// pour finalement faire
// $valTotal - $valHere => 5
}
// C
public override int calculate() {
int val = base.calculate();
val += 5;
return val;
}
jesusonline
Messages postés6814Date d'inscriptiondimanche 15 décembre 2002StatutMembreDernière intervention13 octobre 201029 5 mai 2008 à 20:45
Inutile d'être agressif !
Ce n'est pas possible en C# est je pense une réponse tout à fait acceptable et qui permet de te faire avancer. Comme je n'ai pas la prétention de tout savoir sur tout, je ne voulais pas être catégorique.
Je comprend parfaitement ce que tu demandes (c'est d'ailleurs rare que les questions soient aussi bien posées ;-)). Mais selon moi, conceptuellement ce n'est pas correcte.
Si tu surcharges c'est pour changer le comportement de ta classe, ce que tu voudrais c'est que l'instance de C se comporte de temps en temps comme une instance de C et parfois comme une instance de B.
On pourrait esperer que caster this en B au niveau de l'appel de calculate resoudrais le problème, mis C# ne fonctionne pas comme ça, et heureusement car je ne trouverais pas ca propre.
Cette histoire de cast me fait penser à l'implémentation explicite des interfaces, mais je ne vois pas en quoi cela pourrait t'aider (meme en rien du tout).
Mis à part la reflexion, je ne vois pas de solution, et je trouves que ce tu cherches à faire n'est pas la facon la plus élégante de faire (conceptuellement parlant).
cs_GRenard
Messages postés1662Date d'inscriptionlundi 16 septembre 2002StatutMembreDernière intervention30 juillet 20081 5 mai 2008 à 21:18
Je n'étais pas agressif en tant que tel. Si tu exprimes ton point, tout est OK. Si tu fais juste répondre à la réponse en disant "bad design", ça je trouve cela inutile.
---
Je vois, je ne crois pas que le fait de dire que c'est un mauvais design peut arranger les choses...
Si j'avais mis des virtual et new virtual et des choses comme ça que C# supporte. Vous auriez surement dit "Oh my god, c'est vraiment mélangeant tout ça". Alors pourquoi C# le supporte?
Il y a des méthodes différentes de programmer et certaines sont plus efficaces que d'autres je l'admet mais si un langage supporte quelque chose, c'est parce que c'est possible de le faire.
for(int i = 0; i < myArray.Length; i++) {
if(myArray[i] == false) {
continue;
}
otherArray[i] = "PASS";
}
Pourquoi l'avoir codé ainsi plutôt que d'avoir fait
for(int i = 0; i < myArray.Length; i++) {
if(myArray[i] == true) {
otherArray[i] = "PASS";
}
}
Peut être que dans la logique de ma méthode, les personnes dans mon entreprise qui liront mon code comprendrons mieux le premier code que le 2e et ce sera plus facile de faire une mise à jour.
J'ai écrit tout ça pour dire que... mauvais design ou non, tout le monde ne code pas comme nous :)
Pour en revenir à nos moutons, s'il n'y a vraiment pas de keyword pour accéder à ma méthode, je vais modifier le design.
sebmafate
Messages postés4936Date d'inscriptionlundi 17 février 2003StatutMembreDernière intervention14 février 201437 6 mai 2008 à 10:17
clair que conceptuellement c'est inutile !
en C#, on a seulement :
- this. : instance courante
- base. : type ancestre de l'instance.
Maintenant, ce n'est pas parce que PHP le fait que c'est quelque chose de bien.
Dans ton exemple, tu sembles vouloir implémenter le pattern "Chain Of Responsability" : http://www.dofactory.com/Patterns/PatternChain.aspx
leprov
Messages postés1160Date d'inscriptionvendredi 23 juillet 2004StatutMembreDernière intervention21 octobre 201017 6 mai 2008 à 13:15
il est une solution peu propre et qui risque de te poser des problemes de polymorphisme. si B n'override pas la method mais en fait un new, alors dans ta classe C, base.Calculate appelera A.Calculate, this.Calculate appelra C.calculate, et ((B)this).calculate appelera B.Calculate.
Attention cependant, cette méthode est risquée et tu dois prendre en compte les conséquences de cette méthode sur la résoltuion des méthodes virtuelles dans le reste de ton code (si tu utilise le polymorphisme, sinon pas de soucis). Ca fonctionne, et je ne suis pas choqué outre mesure conceptuellement parlant (A part le fait que niveau maintenabilité cest pas terrible, et que ca force a se poser bcp de questions a chaque fois que tu vas utiliser tes objets et le polymorphisme).
leprov
Messages postés1160Date d'inscriptionvendredi 23 juillet 2004StatutMembreDernière intervention21 octobre 201017 6 mai 2008 à 13:17
sauf erreur de ma part (validé la réponse trop vite), car je ne suis pas entièrement sur qu'il soit possible d'override calculate dans C si B fait un new sur la méthode (je ne sais pas exactement quel choix a été fait a ce niveau, sachant que les deux possibilités sont logiques et acceptables)
leprov
Messages postés1160Date d'inscriptionvendredi 23 juillet 2004StatutMembreDernière intervention21 octobre 201017 6 mai 2008 à 13:23
autre solution (pardon pour le poste multiple), ne rien mettre en virtual, tout en new, et a ce moment tu peux appeler en préfixant dirrectemnt (cest a dire this.calculate, A.Calculate, B.Calculate). je pense que dans ce cas base.calculate appelera B.calculate dans ce cas. cependant le polymorphisme est alors totalement impossible. et en tapant ca je me rend compte que je dis probablement une connerie dans mon premier post car le new doit probablement supprimer le virtual
cs_GRenard
Messages postés1662Date d'inscriptionlundi 16 septembre 2002StatutMembreDernière intervention30 juillet 20081 6 mai 2008 à 17:28
Haha, merci pour tes réponses,
j'ai joué avec ce new et virtual pour essayer un compromis et ça ne fait pas ce que je veux. Il y avait un petit texte à la fin de mon premier poste disant :
"je ne veux pas perdre mon principe de polymorphisme avec mon this"
Dans B.calculate, je fais this.Calculate(), alors j'en ai besoin de mon polymorphisme.
Pour ce qui est de "Chain Of Responsability", non je ne souhaite pas faire ça.
La réponse finale à ceci, si personne d'autre ne se manifeste en faveur est que je vais simplement modifier le design parce que C# ne supporte pas de pointer directement à une classe.
leprov
Messages postés1160Date d'inscriptionvendredi 23 juillet 2004StatutMembreDernière intervention21 octobre 201017 7 mai 2008 à 08:36
dans B, tu dois pouvoir faire B.Calculate. Ou alors appeler la méthode calculate réelle par reflection (si ton but est d'appeler la méthode réelle de this), mais ca devient bien compliqué pour un si petit probleme de conception
cs_GRenard
Messages postés1662Date d'inscriptionlundi 16 septembre 2002StatutMembreDernière intervention30 juillet 20081 7 mai 2008 à 08:44
oui je sais que si je mets des new au lieu de override et que j'utilise la réflexion, je pourrais m'en sortir... Mais c'est de l'overhead pour rien.
Je vais récrire quelque chose... Quitte à duppliquer le code un peu pour que ça fonctionne... en fait c'est que je passe du code PHP vers C#. Alors le but est que ça soit compréhensible pour moi en C# puisque je vais juste fournir un DLL.
Merci à ceux qui se sont donné la peine de répondre des réponses intelligentes :)