2009-11-03 3 views
4

Étant donné une chaîne de texte contenant un nom de type, existe-t-il un moyen d'obtenir le type approprié?RTTI: Puis-je obtenir un type par nom?

Je cherche à faire quelque chose comme ceci:

type 
    TSomeType<T> = class 
    // yadda yadda 
    end; 

procedure DoSomething; 
var 
    obj : TObject; 
begin 
    o := TSomeType<GetTypeByName('integer')>.Create; 
    // do stuff with obj 
end; 

J'ai regardé plusieurs explications RTTI en ligne et regardé à travers les unités Delphi et ne vois pas ce que je cherche. Est-ce possible?

+0

Quel genre de "choses" pensez-vous que vous seriez en mesure de faire avec l'objet que vous créez? –

+0

Récupérez une interface. Cela fait partie d'un système de persistance. – TrespassersW

+0

Qui a dit qu'il a une interface que vous pouvez "saisir"? Si vous en connaissez suffisamment le type pour savoir qu'il implémente une interface spécifique, vous en savez assez pour ne pas avoir besoin de faire ce que votre extrait de code ci-dessus fait. –

Répondre

7

Non, les génériques sont entièrement compiletime.

+0

Eh bien, crud. On dirait que tu as raison. Cela abat une idée assez cool que j'avais. Merci pour l'info. – TrespassersW

+0

Toujours curieux s'il y a un moyen d'obtenir le type du nom, cependant. Même si je ne peux pas l'utiliser exactement comme je le voulais. – TrespassersW

5

Vous pouvez toujours enregistrer vos types dans un type de registre (géré par une liste de chaînes ou un dictionnaire) et créer une fonction usine pour retourner ensuite l'objet approprié. Malheureusement, vous devez savoir à l'avance de quels types vous auriez besoin. Quelque chose de similaire aux fonctions Delphi RegisterClass et FindClass (dans l'unité de classes). Ma pensée est de mettre le type de modèle générique dans la liste directement.

Un exemple d'utilisation possible:

RegisterCustomType('Integer',TSomeType<Integer>); 
RegisterCustomType('String',TSomeType<String>); 

if FindCustomType('Integer') <> nil then 
    O := FindCustomType('Integer').Create; 

EDIT: Voici une implémentation spécifique simple en utilisant un TDictionary de Generics.Collections pour gérer le stockage de registre ... Je vais laisser cela en extraire utile méthodes comme un exercice simple pour le lecteur.

var 
    o : TObject; 
begin 
    TypeDict := TDictionary<String,TClass>.Create; 
    TypeDict.Add('integer',TList<integer>); 
    if TypeDict.ContainsKey('integer') then 
    o := TypeDict.Items['integer'].Create; 
    if Assigned(o) then 
    ShowMessage(o.ClassName); 
end; 

Une autre EDIT: Je donne cette une a été pensée hier soir, et a découvert une autre technique que vous pouvez fusionner dans ce concept. Interfaces Voici un exemple de ne rien faire rapide, mais peut facilement être étendu:

TYPE 
    ITest = interface 
    ['{0DD03794-6713-47A0-BBE5-58F4719F494E}'] 
    end; 

    TIntfList<t> = class(TList<T>,ITest) 
    public 
    function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall; 
    function _AddRef: Integer; stdcall; 
    function _Release: Integer; stdcall; 
    end; 

procedure TForm1.Button7Click(Sender: TObject); 
var 
    o : TObject; 
    fTestIntf : ITest; 
begin 
    TypeDict := TDictionary<String,TClass>.Create; 
    TypeDict.Add('integer',TIntfList<integer>); 
    if TypeDict.ContainsKey('integer') then 
    o := TypeDict.Items['integer'].Create; 
    if Assigned(o) and Supports(o,ITest,fTestIntf) then 
    ShowMessage(o.ClassName); 
end; 

Bien sûr, vous auriez à mettre en œuvre les méthodes QueryInterface, _AddRef et _Release et étendre l'interface pour faire quelque chose de plus utile.

+0

Merci pour ça. C'est à peu près exactement ce que j'ai fait (j'ai eu l'idée de TPersistent de Delphi il y a longtemps). Et votre suggestion est ce que nous avions déjà trouvé (enregistrement de chaque type de modèle) et cela fonctionne bien. J'espérais quelque chose de plus souple et dynamique, mais je n'ai pas l'air de l'avoir. Merci encore. – TrespassersW

+0

Cela peut facilement être fait à la fois flexible et dynamique. La seule chose que vous ne pouvez pas faire est de gérer les types que vous n'avez pas prévus. – skamradt

0

Si vous oubliez les génériques et les types de base, la fonction "RegisterClass" serait utile. Mais cela ne fonctionne pas pour les génériques ou les types de base.

5

La nouvelle unité RTTI de Delphi 2010 permet de récupérer les types déclarés dans la section interface des unités. Pour tout type donné, représenté par une instance TRttiType, la propriété TRttiType.QualifiedName renvoie un nom qui peut être utilisé avec TRttiContext.FindType ultérieurement pour récupérer le type. Le nom qualifié est le nom complet de l'unité (y compris les espaces de noms, s'ils existent), suivi d'un '.', Suivi du nom complet du type (y compris les types externes s'il est imbriqué). Par conséquent, vous pouvez récupérer une représentation du type Integer (sous la forme TRttiType) avec context.FindType('System.Integer').

Mais ce mécanisme ne peut pas être utilisé pour extraire des instanciations de types génériques qui n'ont pas été instanciés au moment de la compilation; L'instanciation à l'exécution nécessite la génération de code d'exécution.

+0

Génial! Merci pour l'info. – TrespassersW

Questions connexes