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:

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

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

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils, TypInfo;
type
  TAnonProc = reference to procedure (const sText:string); // anonymní metoda

procedure Test;
var
  pTest: TAnonProc;
begin
  pTest :=
    procedure (const s: string)
    begin
      writeln(s);
    end;
  pTest ('To je teprve zacatek');
  pTest ('A znovu');
  pTest ('Popojedem');
end;

procedure Test2(p:TAnonProc);
begin
  p('radek 1');
  p('radek 2');
  p('radek 3');
end;

var
  i:Integer;
begin
  Test;
{  Test2(
    procedure (const s:string)
    begin
      writeln(s);
      inc(i);
      writeln(i);
    end);}

end.

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:

procedure test;
var
  i: Integer;
    procedure MyInc; // specializovaná procedura zvetšuje přehlednost
    begin
      inc(i);
    end;
begin
  i := 10;
  MyInc;
  MyInc;
end;

Problém závorek

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

type
  TAnyProc = reference to procedure;
var
  AnyProc: TAnyProc;
  
  //musíte zavolat jako AnyProc(); 
  //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):

function GetMethod: TAnonProc;
begin
  Result :=
    procedure (const s:string)
    begin
      ShowMessage (s);
    end;
end;

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

var
  p: TAnonProc;
begin
  p := GetMethod();
  p('Hello world');
  
  GetMethod()('Hello world');
  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í:

type
  TProc = reference to procedure;
  TProc<T> = reference to procedure (Arg1: T);
  TProc<T1,T2> = reference to procedure (Arg1: T1; Arg2: T2);
  TProc<T1,T2,T3> = reference to procedure (Arg1: T1; Arg2: T2; Arg3: T3);
  TProc<T1,T2,T3,T4> = reference to procedure (Arg1: T1; Arg2: T2; Arg3: T3; Arg4: T4);

procedure UseCode (proc: TProc);
function DoThis (proc: TProc): string;
function DoThat (procInt: TProc<Integer>): string;

type //generické typy
  TFunc<TResult> = reference to function: TResult;
  TFunc<T,TResult> = reference to function ( Arg1: T): TResult;
  TFunc<T1,T2,TResult> = reference to function (Arg1: T1; Arg2: T2): TResult;
  TFunc<T1,T2,T3,TResult> = reference to function (Arg1: T1; Arg2: T2; Arg3: T3): TResult;
  TPredicate<T> = reference to function (Arg1: T): Boolean;

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

 TThreadProcedure = reference to procedure;
 
procedure 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.

Tagy: , ,

Jazyk | Recenze

Komentování ukončeno

Naše nabídka

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).

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.

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.

Poslední komentáře

Comment RSS