2012-02-17 5 views
7

Witam wszystkich :) To jest moje pierwsze pytanie na stackoverflow :)Czy jest możliwe utworzenie wystąpienia TRttiMethod dla TRttiType z TypeKind = tkMethod?

w Delphi XE2 RTTI mamy klasę TRttiMethod i posiada funkcję CreateImplementation() wich pozwala dynamicznie tworzyć procedury lub funkcji z tym samym podpisem i Anonimous metody jako jego ciało.

przy użyciu TRttiContext.getMethods()/getMethod() możemy uzyskać kolekcję metod klasy - kolekcja TRttiMethod.

Dokumentacja mówi (http://docwiki.embarcadero.com/VCL/en/RTTI.TRttiMethod) nie tworzyć bezpośrednio TRTTiMethod i używać getMethods(), aby uzyskać jego wystąpienia.

, więc jeśli mamy instancję TRTTIMethod, możemy dynamicznie utworzyć metodę z tą samą sygnaturą i wywołać ją później.

pytanie brzmi .. na przykład mamy TNotifyEvent ... TRttiContext.getType(typeinfo(TNotifyEvent)) powraca TRttiType instancja obiektu wich został typekind = tkMethod. wiemy, że sygnaturą TNotifyEvent jest procedura (nadawca: TObject) obiektu;

Czy można uzyskać za to TRttiMethod? Chcę dynamicznie utworzyć eventHandler dla zdarzenia przy użyciu TRttiMethod.CreateImplementation() lub może istnieje inny sposób dynamicznego tworzenia realizacji metody?

PS: Pomysł polega na stworzeniu czegoś takiego jak łańcuch zdarzeń. W czasie kompilacji nie znamy typu zdarzenia/sygnatury, więc możemy użyć generycznych do tego jak TEvenChain <TNotifyEvent>. Łańcuch ma kolekcję na zarejestrowanych procedurach obsługi zdarzeń, więc ponieważ nie znamy typu handler'a w czasie kompilacji, musimy go utworzyć dynamicznie, a ten program obsługi otrzymuje tylko parametry i wywołuje z nimi zarejestrowany handler.

zmiana: Oto niektóre kodu (Chodzi o to, aby stworzyć łańcuch obsługi zdarzeń):

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

    TestButton.OnClick := FEventChain.EventHandler; 
end; 

Event1 & event2 sposoby (sender : TObject) formy; nie jest ogólny Przykład (T, w tym przypadku jest NotifyEvent/TChain <TNotifyEvent>) TEventChain.EventHandler jest TNotifyEvent zbyt

TNotifyChain jest

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 właściwość jest mapowany FEvent zmiennej. I FEvent nie jest przypisany, ponieważ zakładamy, że typ zdarzenia/obsługi jest nieznany.

więc w konstruktorze tworzymy wirtualną metodę z TNotifyEvent podpisu i przypisać do niego swój kod 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; 

tutaj używam TestNotifyHandler metody do utworzenia rzeczywistej obsługi z tym samym podpisem wykorzystaniem TRttimethod.CreateImplementation()

więc przypuszczam , istnieje sposób na stworzenie implementacji obsługi zdarzenia w czasie wykonywania przy użyciu TRttiMethodType z TNotifyEvent, ponieważ ma on informacje o typie/liczniku paragrafów i konwencji wywołania rzeczywistego zdarzenia (w ogólnym przypadku).

+0

Jak daleko się teraz dostałeś, proszę udostępnij. – menjaraz

+0

@menjaraz Nie rozwiązałem tego problemu. To nie było dla mnie "prawdziwe" zadanie, "tylko dla zabawy". Napisałem o tym artykuł na moim blogu: http://teran.karelia.pro/articles/item_4508.html (ale oryginalnie w języku rosyjskim); możesz użyć Google, aby przetłumaczyć je na angielski [link] 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

Dziękuję za odpowiedź. – menjaraz

Odpowiedz

4

A TRttiType z typekind TkMethod będzie reprezentowany jako TRttiMethodType. Nie można uzyskać z niego TRttiMethod, ponieważ nie jest to metoda; jest to wskaźnik metody, ale jeśli spojrzysz na metodę TRttiMethodType i jej Invoke, powinieneś znaleźć dokładnie to, czego potrzebujesz.

+0

dzięki za odpowiedź. Nie jestem pewien, że 'TRttiMethodType.Invoke' jest tym, czego potrzebuję; ponieważ jest używany do wywoływania faktycznie istniejących metod obiektu. W moim przypadku nie ma takiej metody i muszę ją wcześniej stworzyć. Dodałem źródło mojej klasy 'TNotifyChain', aby zademonstrować problem. – teran

Powiązane problemy