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).
Jak daleko się teraz dostałeś, proszę udostępnij. – menjaraz
@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
Dziękuję za odpowiedź. – menjaraz