2012-02-17 13 views
7

Ciao a tutti :) E 'la mia prima domanda a StackOverflow :)È possibile creare un'istanza TRttiMethod per TRttiType con TypeKind = tkMethod?

in Delphi XE2 RTTI abbiamo classe TRttiMethod ed ha la funzione CreateImplementation() scomparsa che permette di creare dinamicamente procedura o funzione con la stessa firma e un metodo anonimo come il suo corpo.

utilizzando TRttiContext.getMethods()/getMethod() possiamo ottenere la raccolta di metodi di classe - raccolta di TRttiMethod.

documentazione dice (http://docwiki.embarcadero.com/VCL/en/RTTI.TRttiMethod) non creare TRTTiMethod direttamente e utilizzare getMethods() per ottenere le sue istanze.

quindi, se abbiamo istanza TRTTIMethod, possiamo creare dinamicamente il metodo con la stessa firma e richiamarlo in seguito.

la domanda è .. per esempio, abbiamo TNotifyEvent ... TRttiContext.getType(typeinfo(TNotifyEvent)) rendimenti TRttiType istanza di un oggetto che vanta typekind = tkMethod. sappiamo che la firma di TNotifyEvent è la procedura (mittente: TObject) dell'oggetto;

è possibile ottenere TRttiMethod per questo? Voglio creare dinamicamente eventHandler per l'evento usando TRttiMethod.CreateImplementation() o potrebbe esserci un altro modo per creare dinamicamente l'implementazione del metodo?

PS: l'idea è creare qualcosa come la catena di eventi. Al momento della compilazione non conosciamo il tipo di evento/firma, quindi possiamo utilizzare i generici per questo tipo di TEvenChain <TNotifyEvent>. Chain ha la raccolta sui gestori di eventi registrati, quindi, poiché non conosciamo il tipo di gestore in fase di compilazione, dobbiamo crearlo dinamicamente e il gestore riceve solo i parametri e le chiamate con il gestore registrato.

aggiornamento: ecco qualche codice (idea è di creare catena gestori di eventi):

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

    TestButton.OnClick := FEventChain.EventHandler; 
end; 

Event1 & event2 sono metodi (sender : TObject) di forma; non è esempio generico (T in questo caso è NotifyEvent/Tchain <TNotifyEvent>) TEventChain.EventHandler è TNotifyEvent troppo

TNotifyChain è

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 proprietà è associato a FEvent variabile. E FEvent non è assegnato poiché si presuppone che il tipo di evento/gestore sia sconosciuto.

così nel costruttore creiamo metodo virtuale con TNotifyEvent firma e assegnare il suo codice a 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; 

Qui uso TestNotifyHandler metodo per creare gestore vero e proprio con la stessa firma utilizzando TRttimethod.CreateImplementation()

quindi suppongo , esiste un modo per creare l'implementazione del gestore eventi in fase di esecuzione utilizzando TRttiMethodType da TNotifyEvent perché contiene informazioni sul tipo/conteggio param e sulla convenzione di chiamata dell'evento effettivo utilizzato (nel caso generico).

+0

Quanto lontano hai ottenuto ora, per favore condividi. – menjaraz

+0

@menjaraz Non ho risolto questo problema. Non era un compito "reale" per me, "solo per divertimento". Ho scritto un articolo su questo nel mio blog: http://teran.karelia.pro/articles/item_4508.html (ma è originariamente in russo); puoi utilizzare Google per tradurlo in inglese [collegamento] http://translate.google.com/translate?sl=ru&tl=en&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

Grazie per la risposta. – menjaraz

risposta

4

A TRttiType con type_ind TkMethod verrà rappresentato come TRttiMethodType. Non è possibile ottenere uno TRttiMethod, perché non è un metodo; è un puntatore del metodo, ma se dai un'occhiata allo TRttiMethodType e al suo metodo Invoke, dovresti trovare esattamente ciò di cui hai bisogno.

+0

grazie per la risposta. Non sono sicuro che 'TRttiMethodType.Invoke' è ciò di cui ho bisogno; perché è usato per invocare metodi di oggetti effettivamente esistenti. Nel mio caso non esiste un tale metodo e devo crearlo prima. Ho aggiunto qualche fonte della mia classe 'TNotifyChain' per dimostrare il problema. – teran

Problemi correlati