Quand utiliser les informations de type d'exécution?
-
19-09-2019 - |
Question
Si j'ai plusieurs sous-classes de quelque chose, et un algorithme qui fonctionne sur les instances de ces sous-classes, et si le comportement de l'algorithme varie légèrement en fonction de ce sous-classe particulière une instance est, alors la voie orientée objet le plus habituel de faire est d'utiliser des méthodes virtuelles.
Par exemple, si les sous-classes sont des noeuds DOM, et si l'algorithme est d'insérer un nœud enfant, cet algorithme diffère selon que le nœud parent est un élément DOM (qui peut avoir des enfants) ou le texte DOM (qui ne peut pas .): et si la méthode de insertChildren
peut être virtuel (ou abstrait) dans la classe de base de DomNode
, et mis en oeuvre différemment dans chacune des sous-classes de DomElement
et DomText
Une autre possibilité est de donner les cas une propriété commune, dont la valeur peut être lu: par exemple l'algorithme peut lire la propriété nodeType
de la classe de base DomNode
; ou pour un autre exemple, vous pourriez avoir différents types (sous-classes) de paquet de réseau, qui partagent un en-tête de paquet commun, et vous pouvez lire l'en-tête de paquet pour voir quel type de paquet est.
Je ne l'ai pas utilisé des informations d'exécution de type beaucoup de temps, y compris:
- Les mots-clés
is
etas
en C # - Downcasting
- La méthode Object.GetType en dot net
- L'opérateur
typeid
en C ++
Quand je l'ajout d'un nouvel algorithme qui dépend du type de sous-classe, je tends plutôt que d'ajouter une nouvelle méthode virtuelle à la hiérarchie des classes.
Ma question est, quand il est approprié d'utiliser les informations de type d'exécution, au lieu des fonctions virtuelles?
La solution
Quand il n'y a pas d'autre solution. Les méthodes virtuelles sont toujours préférées, mais parfois ils ne peuvent pas être utilisés. Il y a deux raisons pour lesquelles cela pourrait se produire mais la plus commune est que vous ne disposez pas du code source des classes que vous voulez travailler avec ou vous ne pouvez pas les changer. Cela se produit souvent lorsque vous travaillez avec l'ancien système ou avec bibliothèque commerciale source fermée.
Dans .NET, il peut arrive aussi que vous devez charger de nouvelles assemblées à la volée, comme plug-ins et vous avez généralement pas de cours de base, mais doivent utiliser quelque chose comme duck typing.
Autres conseils
En C ++, parmi d'autres cas obscurs (qui traitent principalement avec des choix de conception inférieurs), RTTI est un moyen de mettre en œuvre ce qu'on appelle méthodes multi-.
Cette construction ( « est » et « comme ») sont très familiers pour les développeurs Delphi, car les gestionnaires d'événements habituellement des objets baissés à un ancêtre commun. Pour exemple d'événement OnClick passe le seul argurment Sender: TObject quel que soit le type de l'objet, que ce soit TButton, TListBox ou tout autre. Si vous voulez en savoir un peu plus sur cet objet, vous devez y accéder via « comme », mais afin d'éviter une exception, vous pouvez vérifier avec « est » avant. Cette downcasting permet la liaison de type de conception des objets et des méthodes qui ne pouvaient pas être possible avec un contrôle strict de type de classe. Imaginez que vous voulez faire la même chose si l'utilisateur clique sur le bouton ou ListBox, mais s'ils nous fournissent différents prototypes de fonctions, il ne pouvait pas être possible de les lier à la même procédure.
Dans le cas plus général, un objet peut appeler une fonction qui informe que l'objet par exemple a changé. Mais à l'avance, il quitte la destination la possibilité de le connaître « personnellement » (et à travers comme), mais pas nécessairement. Il le fait en passant soi comme un ancêtre le plus commun de tous les objets (TObject dans le cas Delphi)
dynamic_cast <>, si je me souviens bien, est en fonction RTTI. Certaines interfaces externes obscures peuvent également compter sur RTTI quand un objet est passé à travers un pointeur vide (pour une raison quelconque que pourrait se produire).
Cela étant dit, je ne l'ai pas vu typeof () dans la nature en 10 ans de travaux d'entretien pro C ++. (Heureusement).
Vous pouvez consulter plus efficace C # pour un cas où la vérification du type d'exécution est OK.
Article 3. Les algorithmes génériques sont spécialisés Utilisation du type Vérification à l'exécution
Vous pouvez facilement réutiliser les médicaments génériques par spécifiant simplement de nouveaux paramètres de type. Une nouvelle instanciation avec nouveau type paramètres signifie un nouveau type comportant des fonctionnalités similaires.
Tout cela est très bien, parce que vous écrivez moins de code. Cependant, étant parfois des moyens plus génériques qui ne prennent pas avantage d'un plus précis, mais nettement supérieur, l'algorithme. Le C # règles linguistiques prennent en compte. Il suffit pour vous de reconnaître que votre algorithme peut être plus efficaces lorsque les paramètres de type ont une plus grande capacité, puis écrire ce code spécifique. En outre, la création d'un second type générique spécifie des contraintes différentes ne fonctionne pas toujours. Générique sont basées sur la instanciations type d'un objet lors de la compilation, et pas le type d'exécution. Si vous ne parvenez pas à tenir compte, vous pouvez manquer efficacité possibles.
Par exemple, supposons que vous écrivez une classe qui fournit une énumération inverse l'ordre sur une séquence d'éléments représentés par IEnumerable
Mais en général, vous devriez examiner attentivement la vérification du type d'exécution et veiller à ce qu'il ne viole pas Liskov Substituion Principe.