2010-04-01 3 views
4

Sur la base d'une réponse à une précédente post, j'étudie la possibilité de la conception suivanteDelphi: RTTI et TObjectList <TObject>

TChildClass = class(TObject) 
private 
    FField1: string; 
    FField2: string; 
end; 

TMyClass = class(TObject) 
private 
    FField1: TChildClass; 
    FField2: TObjectList<TChildClass>; 
end; 

Maintenant, dans le monde réel, TMyClass aura 10 différentes listes comme celle-ci , donc je voudrais pouvoir traiter ces listes en utilisant RTTI. Cependant, je ne suis pas intéressé par les autres champs de cette classe, donc je dois vérifier si un certain champ est une sorte de TObjectList. Voilà ce que j'ai jusqu'à présent:

procedure InitializeClass(RContext: TRttiContext; AObject: TObject); 
var 
    ROwnerType: TRttiType; 
    RObjListType: TRttiType; 
    RField:  TRttiField; 
    SchInf:  TSchemaInfoDetail; 
begin 
ROwnerType := RContext.GetType(AObject.ClassInfo); 
RObjListType := RContext.GetType(TObjectList<TObject>); 
for RField in ROwnerType.GetFields do begin 
    // How do I check if the type of TMyClass.FField2 (which is TObjectList<TChildClass>) is some sort of TObjectList? 
end; 

De toute évidence, RField.FieldType <> RObjListType.FieldType. Cependant, ils ont une certaine relation, n'est-ce pas? Il semble horrible (et faux!) De faire un chèque très élaboré pour les fonctionnalités communes afin de rendre hautement probable que RField.FieldType est en fait un TObjectList.

Pour être honnête, je suis tout à fait mal à l'aise avec les génériques, la question pourrait être très naïve. Cependant, je suis plus qu'heureux d'apprendre. La solution ci-dessus est-elle possible à mettre en œuvre? TIA!

+0

Merci Mason. MARQUAGE cela comme un 2010-problème a été un peu exagéré, je suppose. – conciliator

Répondre

5

Chaque instanciation générique est unique et n'a aucune relation avec d'autres instanciations par rapport à RTTI. Parce que Delphi ne peut pas instancier types génériques lors de l'exécution, il n'y a pas d'équivalent à, par exemple GetGenericTypeDefinition de .NET. Le mieux que vous puissiez faire est de regarder la forme du type - par ex. met-il en œuvre GetEnumerator, Add etc.

Cela peut également être suffisamment flexible pour gérer les types de collecte généraux, pas seulement ceux qui sont instanciés de TObjectList<T>. C# fait quelque chose de similaire avec sa collection initializers - il recherche une méthode Add et insère des appels à elle:

http://msdn.microsoft.com/en-us/library/bb384062.aspx

+0

Merci Barry! Je pense que je vais chercher une méthode Add comme vous l'indiquez. +1 :) – conciliator

1

Delphi peut instancier types génériques lors de l'exécution. Le problème est que les types génériques ne sont généralement pas tenues dans les informations d'exécution. Si vous détenez une var globale du type spécifique (TObjectList < TChildClass> dans votre cas), instanciez (et libérez) dans la section initialisation les informations d'exécution de cette classe spécifique ne seront pas supprimées par l'éditeur de liens et vous pourrez l'instancier dynamiquement plus tard. (Vous devez fournir le nom qualifié complet des classes pour context.findType() pour fonctionner correctement.) J'ai passé un certain temps à comprendre comment cela peut être fait et je ne suis certainement pas satisfait, mais puisque je n'ai pas trouvé une autre façon que je dois faire avec pour l'instant. Si quelqu'un connaît une meilleure façon de le faire, faites le moi savoir.

Questions connexes