Rzutowanie metod

Deti

Nie raz pewnie zdarzyło się, że masz pełno procedur / funkcji w swoich programach i trzeba je uruchamiać w zależności od wywołania. Pokaże tu jak odpalić daną metodę w bardziej dynamiczny sposób.

Najpierw aby zrozumieć co tu robimy - stwórz kilka procedur w swoim programie np.:

procedure MyProc1;
procedure MyProc2;
procedure MyProc3;

Dodaj te zapisy do części interface, a następnie dodaj jakieś przykładowe instrukcje do implementacji. Ale uwaga!: procedury muszą być zadeklarowane w sekcji "published" aby można było na nie rzutować. Gdy już to zrobisz.. - wstaw na przykład na formę button oraz kontrolkę TEdit, niech się nazywają Button1 oraz odpowiednio Edit1. I jeszcze jedna rzecz: wszystkie te 3 procedury są jednego typu ... - dodaj też nowy typ, który będzie odpowiadał tej właśnie budowie metody:

type
  TProcedureType = Procedure of Object;

Zrobimy teraz tak, aby po kliknięciu na Button1 wywołała się ta procedura, której nazwa widnieje w naszej kontrolce. Obsługujemy zatem standardowo zdarzenie Button1.OnClick:

procedure TForm1.Button1Click(Sender: TObject);
var
  ProcRelay : TProcedureType;
begin
  @ProcRelay:= MethodAddress(Edit1.Text);
   if @ProcRelay= nil then
    ShowMessage('Nie ma takiej metody')
  else
  ProcRelay;
 end;

Jak widać nie jest to specjalnie trudne - najpierw tworzymy sobie zmienną, która będzie wskazywac na naszą metodę. Później przypisujemy jej adres tej metody, którą sobie ktoś wybrał w kontrolce Edit1. Później sprawdzamy, czy w ogóle taka metoda istnieje - jeśli nie to zostaniemy o tym odpowiednio poinformowani :) Jeśli natomiast wszystko pójdzie zgodnie z oczekiwaniami - odpalamy naszą procedurę.

Jak widać sposób ten zaoszczędzi nam nieco zbędnego kodu i wprowadzi trochę zaawansowanego dynamizmu do programu.. :)

Można też zrobić to jako odzielna funkcja, której na wejściu bedzie podawana metoda, a zwracać będzie wartość wartość typu Boolean (True - metoda istnieje, False - metoda nie istnieje) ... przy pierwszej możliwości funkcja ta może oczywiscie daną metodę odpalać.

Również zamiast "Procedure of Object" można dać inny dowolny typ procedury, funkcji...

8 komentarzy

Witam.
Jak ProcRelay : TProcedureType; przechować w var Event: TNotifyEvent;?

No fajne... ale aby nie pisac za duzo, to wszedzie tam gdzie chce sie wykorzystac wskazniki na funkcje, stosuje sie "funktory"... ot, taki idiom w programowaniu obiektowym. Pozdrawiam.

No fajne... ale aby nie pisac za duzo, to wszedzie tam gdzie chce sie wykorzystac wskazniki na funkcje, stosuje sie "funktory"... ot, taki idiom w programowaniu obiektowym. Pozdrawiam.

Witam.
Dla Milka:
Oto rzutowanie funkcji z parametrem:

Założenie: procedura (lub funkcja) np taka:

procedure proc1(i:integer;x:string);

Type TProc=procedure(i:integer;x:string) of object;
i potem

var met:Tmethod;
  p:Pointer;
  pr:Tproc;
begin
 p:=Tform.MethodAddress(\'proc1\');
 met.code:=p;
 p:=form1;
 met.data:=p;//to nie jest konieczne ponieważ nasza metoda nie 
                    //wykożystuje parametru self w swojej definicji, ale dajmy
 pr:=TProc(met);
 pr(1,\'ala\');
end;

Pragnę dodać, iż mimo iż w danej chwili jakiś objekt może mieć dostęp do dwóch metod (np z parametrem lub bez), to MethodAdress jest metodą klasy. Oznacza to, iż pobiera adres metody z typu a nie z objektu(choć z objektu też zadziała). A Dana klasa nie możę mieć dwóch opublikowanych metod o takiej samej nazwie(przeciążonych). Mówiąc inaczej jak dla objektu mamy możliwość przez np form1.procedura wybrać dwie procedury do dostęp i tak mamy tylko do jednej(do tej zadeklarowanej w Typie takim jaki jest form1). Żeby wam jeszcze troche namieszać w głowie to powiem że to idealna metoda aby obejść metody statyczne. Przykład:
Klasa1 ma procedure do;
Klasa2(dziedzicząca od klasa1) definiuje nową procedure do. Obie są statyczne. Teraz mamy objekt: var ob:Klasa1; i potem ob:=TKlasa2.create to wywołując ob.do wywołamy procke z klasa1(bo nie są virtualne). MethodAddress (ale nie z klasy tylko już z ob) mamy dostęp do metody Klasa2.do
Pozdrawiam:)

szkoda troszkę, że poszedłeś na łatwizne :( trzeba było opisać to samo tylko z wykorzystaniem funkcji z parametrem, gdyż częściej występują w programach niż proceduty bez para,etru...

ps. najlepiej jakbyś poprawil

Hmm, może sprawdź, jak VCL to robi, to może się uda?? :) ASM i cierpliwość :)

niezłe, choć osobiście szukam czegoś takiego na typy messejdżów ;] - np. WM_QUIT, WM_SHOW itd. jest jakaś podobna rzecz?

Bardzo dobre! Rzeczywiście wiele kodu i CZASU takie coś pozwala zaoszczędzić... Trafny artykuł!