Delphi 2009 - Anonymní metody

vložil Radek Červinka 6. ledna 2010 01:29

Delphi už dlouho má procedurální typy (tj. typu procedura nebo funkce, v podstatě pointer) a ukazatele na metody ( tj. typ pointer na metodu). To druhé je základem celé VCL - kdykoliv deklarujete třeba OnClick obsluhu jedná se právě o druhý případ. První případ je používaný méně, ale třeba já ho často používám pro různé callback funkce atd.

Anonymní metody rozšiřují stávající stav, kdy místo jména procedury nebo metody prostě napíšete kód. Navíc se v takovém případě mění platnost lokálních proměnných.

Pro připomenutí deklarace:

    1type
    2   TLogProc = procedure (const sText:string); // první případ
    3   TLogMethod = procedure (const sText:string) of object; // druhý případ
    4   
    5   TAnonProc = reference to procedure (const sText:string); // anonymní metoda

Jednoduchý neužitečný příklad

    1program Project1;
    2
    3{$APPTYPE CONSOLE}
    4
    5uses
    6  SysUtils, TypInfo;
    7type
    8  TAnonProc = reference to procedure (const sText:string); // anonymní metoda
    9
   10procedure Test;
   11var
   12  pTest: TAnonProc;
   13begin
   14  pTest :=
   15    procedure (const s: string)
   16    begin
   17      writeln(s);
   18    end;
   19  pTest ('To je teprve zacatek');
   20  pTest ('A znovu');
   21  pTest ('Popojedem');
   22end;
   23
   24procedure Test2(p:TAnonProc);
   25begin
   26  p('radek 1');
   27  p('radek 2');
   28  p('radek 3');
   29end;
   30
   31var
   32  i:Integer;
   33begin
   34  Test;
   35{  Test2(
   36    procedure (const s:string)
   37    begin
   38      writeln(s);
   39      inc(i);
   40      writeln(i);
   41    end);}
   42
   43end.

Dobré ne? Deklarujeme anonymní metodu pTest a hnedle do ní přiřadíme kus kódu. Pak ho zavoláme. Jenže místo zavolání ho můžeme předat někam dál, stačí jen deklarovat metodu s parametrem TAnonProc a hned nám naše malá procedurka může cestovat programem - viz zatím zapoznámkovaná Test2.

Lokální proměnné

Nyní přichází čas na Test2, pokud odkomentujete její volání dostanete následující výstup:

To je teprve zacatek
A znovu
Popojedem
radek 1
1
radek 2
2
radek 3
3

Všimněte si prosím, že proměnná i je deklarovaná v hlavním programu, ale v Test2 je třikrát zavolaná a tudíž je pokaždé zvětšena o 1.

V podstatě je to rozšířením starých známých vložených procedur:

    1procedure test;
    2var
    3  i: Integer;
    4    procedure MyInc; // specializovaná procedura zvetšuje přehlednost
    5    begin
    6      inc(i);
    7    end;
    8begin
    9  i := 10;
   10  MyInc;
   11  MyInc;
   12end;

Problém závorek

Zde pokud vím vzniká poprvé problém závorek při volání metody bez parametrů.

    1type
    2  TAnyProc = reference to procedure;
    3var
    4  AnyProc: TAnyProc;
    5  
    6  //musíte zavolat jako AnyProc(); 
    7  //jinak si kompilátor bude myslet, že chcete referenci a ne volání

Podobně pokud máte funkci, která vrací anonymní metodu (opět zcestný příklad):

    1function GetMethod: TAnonProc;
    2begin
    3  Result :=
    4    procedure (const s:string)
    5    begin
    6      ShowMessage (s);
    7    end;
    8end;

Jak tedy zavoláme vrácenou funkci? Máme tyto možnosti:

    1var
    2  p: TAnonProc;
    3begin
    4  p := GetMethod();
    5  p('Hello world');
    6  
    7  GetMethod()('Hello world');
    8  GetMethod.Invoke('Hello world'); // Invoke přidáno kompilátorem v případě bez závorek

Předpřipravené anonymní metody

V unitu SysUtils je několik hotových řešení:

    1type
    2  TProc = reference to procedure;
    3  TProc<T> = reference to procedure (Arg1: T);
    4  TProc<T1,T2> = reference to procedure (Arg1: T1; Arg2: T2);
    5  TProc<T1,T2,T3> = reference to procedure (Arg1: T1; Arg2: T2; Arg3: T3);
    6  TProc<T1,T2,T3,T4> = reference to procedure (Arg1: T1; Arg2: T2; Arg3: T3; Arg4: T4);
    7
    8procedure UseCode (proc: TProc);
    9function DoThis (proc: TProc): string;
   10function DoThat (procInt: TProc<Integer>): string;
   11
   12type //generické typy
   13  TFunc<TResult> = reference to function: TResult;
   14  TFunc<T,TResult> = reference to function ( Arg1: T): TResult;
   15  TFunc<T1,T2,TResult> = reference to function (Arg1: T1; Arg2: T2): TResult;
   16  TFunc<T1,T2,T3,TResult> = reference to function (Arg1: T1; Arg2: T2; Arg3: T3): TResult;
   17  TPredicate<T> = reference to function (Arg1: T): Boolean;

Třída TThread byla rozšířena o

    1TThreadProcedure = reference to procedure;
    2 
    3procedure Synchronize(AThreadProc: TThreadProcedure); overload;

Anonymní metody mají hodně použití a mohou zpřehlednit kód (ale i naopak). Mimochodem jedním z hlavních cílů bylo podpora pro budoucí Parallel library, tj. lepší využití víceprocesorových systémů v budoucích verzích.


Nabízíme Delphi školení na různá témata, primárně ve Vaší firmě.

Tagy: , ,

Jazyk | Recenze

Komentování ukončeno

Naše nabídka

Partial English version.

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy nebo burzy práce).

Pokud chcete podpořit tento server libovolnou částkou, můžete použít PayPal. Moc děkuji.

Delphi Certified Developer

O Delphi.cz

Delphi je jediný moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64 , Mac OSX a na iPhone a Android (s výhledem na další platformy díky FireMonkey) na současném trhu (včetně Windows 8.1).

V současnosti je světová komunita přes dva miliónů vývojářů.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Anketa

Poslední komentáře

Comment RSS