Chaque fois que je remplace une méthode d'une classe de base, autre que mon implémentation de cette méthode, je semble avoir 3 choix.
1) Appelez base.Method (), puis fournissez mon implémentation.
2) Fournissez mon implémentation puis appelez base.Method ()
3) Fournissez simplement mon implémentation.
Récemment, en utilisant une bibliothèque, j'ai réalisé quelques bugs qui ont été introduits en raison de la non implémentation de la méthode comme prévu par la bibliothèque. Je ne sais pas si c'est mauvais de la part d'une bibliothèque, ou quelque chose de mal dans ma compréhension.
Je prendrai un exemple.
public class ViewManager {
public virtual void Customize(){
PrepareBaseView();
}
}
public class PostViewManager {
public override void Customize(){
base.Customize();
PreparePostView();
}
}
public class PreViewManager {
public override void Customize(){
PreparePreView();
base.Customize();
}
}
public class CustomViewManager {
public override void Customize(){
PrepareCustomView();
}
}
Ma question ici est la suivante: comment une classe enfant pourrait-elle savoir (sans jeter un œil à l'implémentation de la classe de base) quel ordre (ou option) est attendu par la classe parent? Existe-t-il un moyen par lequel la classe parent pourrait appliquer l'un des trois suppléants à toutes les classes dérivées?
comment une classe enfant pourrait-elle savoir (sans jeter un œil à l'implémentation de la classe de base) quel ordre (ou option) est attendu par la classe parent?
Il n'y a aucun moyen de "savoir" cela lorsque vous sous-classe et remplacez une méthode. Une documentation appropriée est vraiment la seule option ici.
Existe-t-il un moyen par lequel la classe parent pourrait appliquer l'un des trois suppléants à toutes les classes dérivées?
La seule option ici est d'éviter le problème. Au lieu de permettre à la sous-classe de remplacer la méthode, elle peut être déclarée non virtuelle et appeler une méthode virtuelle à l'endroit approprié. Par exemple, si vous voulez appliquer ces sous-classes "appelez d'abord votre version", vous pouvez faire:
public class BaseClass {
public void Method() // Non-virtual
{
// Do required work
// Call virtual method now...
this.OnMethod();
}
protected virtual void OnMethod()
{ // Do nothing
}
}
Les sous-classes peuvent alors "remplacer" OnMethod et fournir des fonctionnalités qui se produisent après le travail de "méthode".
La raison en est que les méthodes virtuelles sont conçues pour permettre à une sous-classe de remplacer complètement l'implémentation de la classe parente. C'est fait exprès. Si vous souhaitez empêcher cela, il est préférable de rendre la méthode non virtuelle.
C'est pourquoi je pense que les méthodes virtuelles sont dangereuses lorsque vous les expédiez dans une bibliothèque. La vérité est que vous ne savez jamais vraiment sans regarder la classe de base, parfois vous devez allumer reflektor, lire la documentation ou l'aborder avec essais et erreurs.
Lorsque j'écris du code moi-même, je me suis toujours fatigué de suivre la règle qui dit:
Les classes dérivées qui remplacent la méthode virtuelle protégée ne sont pas tenues d'appeler l'implémentation de la classe de base. La classe de base doit continuer à fonctionner correctement même si son implémentation n'est pas appelée.
Ceci est tiré de http://msdn.Microsoft.com/en-us/library/ms229011.aspx , cependant c'est pour la conception d'événements bien que je crois avoir lu ceci dans le livre Framework Design Guidelines ( http://www.Amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756 ).
Cependant, ce n'est évidemment pas vrai, les formulaires Web ASP.NET par exemple nécessitent un appel de base sur▶Load.
Donc, long et court, cela varie et malheureusement il n'y a pas de moyen instantané de le savoir. En cas de doute, je vais d'abord ignorer l'appel.
La réponse courte est non. Vous ne pouvez pas appliquer dans quel ordre l'enfant appelle la méthode de base, ou s'il l'appelle du tout.
Techniquement, ces informations doivent être incluses dans la documentation de l'objet de base. Si vous devez absolument exécuter du code avant ou après le code de la classe enfant, vous pouvez procéder comme suit:
1) Créez une fonction non virtuelle dans la classe de base. Appelons ça MyFunction
2) Créez une fonction virtuelle protégée dans la classe de base. Appelons ça _MyFunction
3) Demandez aux classes dérivées d'étendre la méthode _MyFunction.
4) Demandez à MyFunction d'appeler _MyFunction et exécutez le code dont il a besoin avant ou après l'appel.
Cette méthode est moche et nécessiterait beaucoup de code supplémentaire, donc je recommande simplement de mettre une note dans la documentation.
Les exigences de la classe de base doivent être documentées par le concepteur de la bibliothèque. Ce problème est la raison pour laquelle certaines bibliothèques contiennent principalement des classes scellées.