Delphi.cz

Český portál Delphi

Delphi 2009 - Anonymní metody

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.

Datum: 2010-01-06 00:29:00 Tagy: kompilátor, Delphi 2009, anonymni metody

Jazyk Recenze