Comme d'autres réponses ont noté, c'est par la conception.
Considérons un moins compliquées exemple:
class Animal
{
public virtual void Eat(Apple a) { ... }
}
class Giraffe : Animal
{
public void Eat(Food f) { ... }
public override void Eat(Apple a) { ... }
}
La question est pourquoi giraffe.Eat(apple)
résout Giraffe.Eat(Food)
et pas du virtuel, Animal.Eat(Apple)
.
C'est une conséquence de deux règles:
(1) Le type de récepteur est plus important que le type d'un argument lors de la résolution des surcharges.
J'espère que c'est clair pourquoi ce doit être le cas. La personne qui écrit la classe dérivée est strictement plus de connaissances que la personne qui écrit la classe de base, parce que la personne qui écrit la classe dérivée utilisé la classe de base, et non pas vice versa.
La personne qui a écrit Giraffe
dit: "j'ai un moyen pour un Giraffe
manger toute la nourriture", et qui nécessite des connaissances particulières de l'intérieur de la girafe de la digestion. Cette information n'est pas présente dans la classe de base de la mise en œuvre, qui ne sait que manger des pommes.
Afin de résolution de surcharge doit toujours privilégier le choix d'une méthode d'une classe dérivée sur le choix d'une méthode d'une classe de base, quel que soit le betterness de l'argument des conversions de type.
(2) le Choix de remplacer ou de ne pas surcharger une méthode virtuelle n'est pas une partie du public de la surface d'une classe. C'est un privé détail d'implémentation. Par conséquent, aucune décision ne doit être fait quand vous faites résolution de surcharge qui allait changer en fonction de si oui ou non une méthode est substituée.
Résolution de surcharge ne doit jamais dire "je vais choisir virtuel Animal.Eat(Apple)
parce qu'il a été remplacé".
Maintenant, vous pourriez vous dire "OK, supposons que je suis à l'intérieur de la Girafe quand je fais l'appel." Code à l'intérieur de la Girafe possède toutes les connaissances de privé détails de mise en œuvre, à droite? Il peut donc prendre la décision de faire appel virtuel Animal.Eat(Apple)
au lieu de Giraffe.Eat(Food)
lorsqu'ils sont confrontés à giraffe.Eat(apple)
, droite? Parce qu'il sait qu'il y a une mise en œuvre qui comprend les besoins des girafes que manger des pommes.
C'est un remède pire que le mal. Maintenant, nous avons une situation où identiques code a différents comportements en fonction de l'endroit où elle de course! Vous pouvez imaginer avoir un appel à l' giraffe.Eat(apple)
en dehors de la classe, refactoriser le code de sorte qu'il est à l'intérieur de la classe, et tout à coup observables changements de comportement!
Ou, pourrait-on dire, hey, je me rends compte que ma Girafe logique est en fait assez général pour passer à une classe de base, mais pas à l'Animal, donc je vais refactoriser mon Giraffe
code pour:
class Mammal : Animal
{
public void Eat(Food f) { ... }
public override void Eat(Apple a) { ... }
}
class Giraffe : Mammal
{
...
}
Et maintenant, tous les appels d' giraffe.Eat(apple)
à l'intérieur d' Giraffe
coup à de différentes de résolution de surcharge comportement après le refactoring? Ce serait très inattendu!
C# est un pit-de-la réussite de la langue; nous voulons assurez-vous que simple refactorings comme la modification de l'emplacement dans une hiérarchie, une méthode est surchargée de ne pas provoquer des changements subtils dans le comportement.
En résumé:
- Résolution de surcharge priorise les récepteurs sur les autres arguments, car l'appel de code spécialisé qui connaît le fonctionnement interne du récepteur est mieux que d'appeler plus générale de code qui ne fonctionne pas.
- Si et lorsqu'une méthode est substituée n'est pas considéré comme lors de la résolution de surcharge; toutes les méthodes sont traitées comme si elles étaient jamais remplacé pour des fins de résolution de surcharge. C'est un détail d'implémentation qui ne font pas partie de la surface de la type.
- La surcharge de résolution de problèmes sont résolus -- modulo l'accessibilité des cours! -- de la même façon, peu importe où le problème se produit dans le code. Nous n'avons pas un algorithme pour la résolution où le récepteur est du type de l'contenant le code, et un autre pour quand l'appel est dans une classe différente.
Réflexions supplémentaires sur des questions connexes peuvent être trouvés ici: https://ericlippert.com/2013/12/23/closer-is-better/ et ici https://blogs.msdn.microsoft.com/ericlippert/2007/09/04/future-breaking-changes-part-three/