2012-02-17 3 views
7

Salut à tous :) il est ma première question à stackoverflow :)Est-il possible de créer une instance TRttiMethod pour TRttiType avec TypeKind = tkMethod?

dans Delphi XE2 RTTI nous avons la classe TRttiMethod et il a une fonction CreateImplementation() Wich permet de créer de façon dynamique la procédure ou la fonction avec la même signature et une méthode anonimous comme corps. En utilisant TRttiContext.getMethods()/getMethod() on peut obtenir la collection de méthodes de classe - collection de TRttiMethod. La documentation indique (http://docwiki.embarcadero.com/VCL/en/RTTI.TRttiMethod) de ne pas créer directement TRTTiMethod et d'utiliser getMethods() pour obtenir ses instances. Donc, si nous avons l'instance TRTTIMethod, nous pouvons créer dynamiquement une méthode avec la même signature et l'invoquer plus tard.

la question est .. par exemple, nous avons TNotifyEvent ... TRttiContext.getType(typeinfo(TNotifyEvent)) retours TRttiType exemple wich objet a TypeKind = tkMethod. nous savons que la signature de TNotifyEvent est la procédure (expéditeur: TObject) de l'objet;

est-il possible d'obtenir TRttiMethod pour cela? Je souhaite créer dynamiquement eventHandler pour l'événement en utilisant TRttiMethod.CreateImplementation() ou peut-être existe-t-il un autre moyen de créer dynamiquement une implémentation de méthode? PS: l'idée est de créer quelque chose comme une chaîne d'événements. Au moment de la compilation, nous ne connaissons pas le type/la signature de l'événement, donc nous pouvons utiliser des génériques pour cela, comme TEvenChain <TNotifyEvent>. La chaîne a une collection sur les gestionnaires d'événements enregistrés, donc parce que nous ne connaissons pas le type de gestionnaire au moment de la compilation, nous devons le créer dynamiquement, et ce gestionnaire obtient seulement ses paramètres et appelle le gestionnaire enregistré avec eux.

mise à jour: ici est un code (idée est de créer la chaîne de gestionnaires d'événements):

procedure TMainForm.FormCreate(Sender: TObject); 
begin 
    FEventChain := TNotifyChain.Create(); 
    FEventChain.AddHandler(event1); 
    FEventChain.AddHandler(event2); 

    TestButton.OnClick := FEventChain.EventHandler; 
end; 

Event1 & event2 sont des méthodes (sender : TObject) de la forme; ce n'est pas exemple générique (T dans ce cas est NotifyEvent/Tchain <TNotifyEvent>) TEventChain.EventHandler est TNotifyEvent trop

TNotifyChain est

TNotifyChain = class(TObject) 
    strict private 
    FEvent : TNotifyEvent; 
    FItems : TList<TNotifyEvent>; 

    FCtx : TRttiContext; 
    public 
    procedure TestNotifyHandler(sender : TObject); virtual; abstract; 

    constructor Create(); 
    procedure AddHandler(eh : TNotifyEvent); 
    property EventHandler : TNotifyEvent read FEvent; 
end; 

EventHandler propriété est mappée à la variable FEvent. Et FEvent n'est pas affecté car nous supposons que le type d'événement/gestionnaire est inconnu.

donc dans le constructeur, nous créons la méthode virtuelle avec la signature TNotifyEvent et assignez son code à FEvent:

constructor TNotifyChain.Create(); 
var st: TRttiType; 
    //et : TRttiMethodType; 
    Callback : TMethodImplementationCallback; 
    rttiMethod : TRttiMethod; 
    m : TMethod; 
    mi : TMethodImplementation; 
begin 
    inherited; 
    FItems := TList<TNotifyEvent>.Create(); 

    FCtx := TRttiContext.Create(); 

    //et := FCtx.GetType(typeinfo(TNotifyEvent)) as TRttiMethodType; 
    st := FCtx.GetType(self.ClassType); 


    rttiMethod := st.GetMethod('TestNotifyHandler'); 

    Callback := procedure(UserData: Pointer; 
         const Args: TArray<TValue>; 
         out Result: TValue) 
      var i : integer; 
       e : TMethod; 
      begin 

       for i := 0 to FItems.Count - 1 do begin 
        e := TMethod(Fitems[i]); 
        result := Invoke(e.Code, args, rttiMethod.CallingConvention, nil); 
       end; 
      end; 


    mi := rttiMethod.CreateImplementation(self, Callback); 

    m.data := self; 
    m.Code := mi.CodeAddress; 
    FEvent := TNotifyEvent(m); 
end; 

J'utilise ici TestNotifyHandler méthode pour créer gestionnaire réel avec la même signature en utilisant TRttimethod.CreateImplementation()

Je suppose que oui , il existe un moyen de créer l'implémentation du gestionnaire d'événements au moment de l'exécution en utilisant TRttiMethodType de TNotifyEvent car il contient des informations sur les paramètres type/count et la convention d'appel de l'événement réel utilisé (dans le cas générique).

+0

Jusqu'où êtes-vous arrivé maintenant? – menjaraz

+0

@menjaraz Je n'ai pas résolu ce problème. Ce n'était pas une "vraie" tâche pour moi, "juste pour m'amuser". J'ai écrit un article à ce sujet dans mon blog: http://teran.karelia.pro/articles/item_4508.html (mais il est à l'origine en russe); vous pouvez utiliser Google pour traduire en anglais [link] http://translate.google.com/translate?sl=ru&tl=fr&js=n&prev=_t&hl=ru&ie=UTF-8&layout=2&eotf=1&u=http%3A%2F% 2Fteran.karelia.pro% 2Farticles% 2Fitem_4508.html & act = url – teran

+0

Merci d'avoir répondu. – menjaraz

Répondre

4

Un TRttiType avec typekind TkMethod va être représenté comme TRttiMethodType. Vous ne pouvez pas en obtenir un TRttiMethod, parce que ce n'est pas une méthode; C'est un pointeur de méthode, mais si vous jetez un oeil à TRttiMethodType et sa méthode Invoke, vous devriez trouver exactement ce dont vous avez besoin.

+0

merci pour la réponse. Je ne suis pas sûr que 'TRttiMethodType.Invoke' est ce dont j'ai besoin; car il est utilisé pour invoquer des méthodes d'objet existantes. Dans mon cas il n'y a pas une telle méthode et je dois le créer avant. J'ai ajouté une source de ma classe 'TNotifyChain' pour montrer le problème. – teran

Questions connexes