Il est bien connu de ceux qui connaissent l'histoire que C # et le framework .NET ont commencé comme étant essentiellement "Delphi réécrit pour ressembler à Java", architecturé par le développeur en chef de Delphi, Anders Hejlsberg. Les choses ont beaucoup divergé depuis lors, mais au début, les similitudes étaient si évidentes qu'il y avait même de sérieuses spéculations selon lesquelles .NET était en fait à l'origine le produit de Borland.
Mais j'ai récemment regardé quelques trucs .NET, et l'une des fonctionnalités les plus intéressantes et utiles de Delphi semble manquer complètement: le concept de classes en tant que type de données de première classe. Pour ceux qui ne le connaissent pas, le type TClass
représente une référence à une classe, similaire au Type
type dans .NET. Mais là où .NET utilise Type
pour la réflexion, Delphi utilise TClass
comme une partie intégrée très importante du langage. Il permet divers idiomes utiles qui n'existent tout simplement pas et ne peuvent pas exister sans lui, tels que les variables de sous-type de classe et les méthodes de classe virtuelle.
Chaque langage OO possède des méthodes virtuelles, dans lesquelles différentes classes implémentent le même concept fondamental d'une méthode de différentes manières, puis la bonne méthode est appelée au moment de l'exécution en fonction du type réel de l'instance d'objet sur laquelle elle est appelée. Delphi étend ce concept aux classes: si vous avez une référence TClass définie comme un sous-type de classe spécifique (c'est-à- class of TMyClass
dire que la variable peut accepter n'importe quelle référence de classe qui hérite TMyClass
, mais pas en dehors de la hiérarchie) qui a des méthodes virtuelles de portée de classe attachées à , ils peuvent être appelés sans instance en utilisant le type réel de la classe. L'application de ce modèle aux constructeurs rend une implémentation Factory triviale, par exemple.
Il ne semble pas y avoir d'équivalent dans .NET. Avec aussi utiles que les références de classe (et en particulier les constructeurs virtuels et autres méthodes de classe virtuelle!), Est-ce que quelqu'un a dit pourquoi ils ont été exclus?
Exemples spécifiques
Désérialisation de formulaire
Delphi VCL enregistre les formulaires au DFM
format, un DSL pour décrire une hiérarchie de composants. Lorsque le lecteur de formulaire analyse les données DFM, il s'exécute sur des objets décrits comme suit:
object Name: ClassName
property = value
property = value
...
object SubObjectName: ClassName
...
end
end
La chose intéressante ici est la ClassName
partie. Chaque classe de composant enregistre son temps TClass
avec le système de streaming de composants initialization
(pensez aux constructeurs statiques, seulement légèrement différents, garantis de se produire immédiatement au démarrage.) Cela enregistre chaque classe dans une chaîne -> TClass hashmap avec le nom de classe comme clé.
Chaque composant descend TComponent
, ce qui a un constructeur virtuel qui prend un seul argument, Owner: TComponent
. Tout composant peut remplacer ce constructeur pour prévoir sa propre initialisation. Lorsque le lecteur DFM lit un nom de classe, il recherche le nom dans la table de hachage susmentionnée et récupère la référence de classe correspondante (ou déclenche une exception s'il n'est pas là), puis appelle le constructeur virtuel TComponent dessus, qui est connu pour être bon car la fonction d'enregistrement prend une référence de classe qui doit descendre de TComponent et vous vous retrouvez avec un objet du type approprié.
À défaut, l'équivalent de WinForms est ... eh bien ... un gros gâchis pour le dire franchement, nécessitant tout nouveau langage .NET pour réimplémenter complètement sa propre forme (de) sérialisation. C'est un peu choquant quand on y pense; comme l'intérêt d'avoir un CLR est de laisser plusieurs langues utiliser la même infrastructure de base, un système de style DFM aurait été parfaitement logique.
Extensibilité
Une classe de gestionnaire d'images que j'ai écrite peut être fournie avec une source de données (comme un chemin d'accès à vos fichiers image), puis charger automatiquement de nouveaux objets image si vous essayez de récupérer un nom qui n'est pas dans la collection mais qui est disponible dans la source de données. Il a une variable de classe typée comme class of
classe d'image de base, représentant la classe de tout nouvel objet à créer. Il est livré avec une valeur par défaut, mais il y a certains points, lors de la création de nouvelles images à des fins spéciales, que les images doivent être configurées de différentes manières. (Création sans canal alpha, récupération de métadonnées spéciales à partir d'un fichier PNG pour spécifier la taille de l'image-objet, etc.)
Cela pourrait être fait en écrivant de grandes quantités de code de configuration et en passant des options spéciales à toutes les méthodes qui pourraient finir par créer un nouvel objet ... ou vous pourriez simplement créer une sous-classe de la classe d'image de base qui remplace une méthode virtuelle où l'aspect en question est configuré, puis utilisez un bloc try / finally pour remplacer temporairement la propriété "classe par défaut" selon vos besoins, puis restaurez-la. Le faire avec des variables de référence de classe est beaucoup plus simple et n'est pas quelque chose qui pourrait être fait avec des génériques à la place.
TClass
est utile, avec un exemple de code? Dans ma recherche Internet rapide sur TClass
, je trouve que cela TClass
peut être transmis comme paramètre. Cela se fait dans .NET en utilisant des génériques. Les méthodes d'usine sont simplement marquées static
en .NET et ne nécessitent pas d'instance de classe pour s'exécuter.
TClass
est une fonctionnalité de langage fondamentale qui nécessite le support du compilateur. Vous ne pouvez pas "écrire le vôtre" sans écrire votre propre langage, et pour .NET même cela ne serait pas suffisant car le modèle d'objet est défini par le CLR, pas par des langages individuels. C'est quelque chose qui doit littéralement faire partie du framework .NET lui-même, ou il ne peut pas exister.