Delphi 2009 - Anonymous methods by Radek Červinka

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,439
Credits
574
Delphi 2009 - Anonymous methods by Radek Červinka
Radek Červinka - 06/Jan/2010
[SHOWTOGROUPS=4,20]
Delphi has long had procedural types (ie, of the procedure or function type, essentially a pointer) and pointers to methods (ie, a pointer to a method). The latter is the basis of the entire VCL - whenever you declare, for example, an OnClick service, this is the second case. The first case is used less, but for example I often use it for various callback functions, etc.

Anonymous methods extend the existing state where you simply write code instead of the name of a procedure or method. In addition, the validity of local variables changes in this case.

To remind the declaration:
Код:
type
  TLogProc   = procedure(const sText: string);           // first case
  TLogMethod = procedure(const sText: string) of object; // second case

  TAnonProc = reference to procedure(const sText: string); // anonymous method

A simple useless example
Код:
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('This is just the beginning');
  pTest('And again');
  pTest('Let''s eat');
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.

Good isn't it? We declare the anonymous method pTest and immediately assign a piece of code to it.

Then we'll call him. But instead of calling it, we can pass it somewhere else, all you have to do is declare a method with the TAnonProc parameter, and immediately our little procedure can travel through the program - see the not-yet-tested Test2.

Local variables
Now it's time for Test2, if you uncomment her call you will get the following output:
Код:
This is just the beginning
And again
I'll eat

Код:
radek 1
1
radek 2
2
radek 3
3

Please note that the variable i is declared in the main program, but in Test2 it is called three times and is therefore incremented by 1 each time.
Basically, it's an extension of the old familiar embedded procedures:
Код:
procedure test;
var
  i: Integer;
  //
  procedure MyInc; // specialized procedure increases clarity
  begin
    inc(i);
  end;
  //
begin
  i := 10;
  MyInc;
  MyInc;
end;

The problem of parentheses
Here, as far as I know, there is the problem of parentheses when calling a method without parameters.
Код:
type
TAnyProc = reference to procedure ;
var
AnyProc: TAnyProc;

// you need to call as AnyProc ();
// otherwise the compiler will think you want a reference and not a call

Similarly, if you have a function that returns an anonymous method (again, a misleading example):
Код:
function GetMethod: TAnonProc;
begin
  Result := procedure(const s: string)
    begin
      ShowMessage(s);
    end;
end;

So how do we call a returned function? We have these options:
Код:
var
  p: TAnonProc;
begin
  p:= GetMethod();
  p('Hello world');

  GetMethod()('Hello world');
  GetMethod.Invoke('Hello world'); // Invoke added by compiler in case without parentheses

Pre-prepared anonymous methods
There are several ready-made solutions in the SysUtils unit:
Код:
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;

The TThread class has been extended by
Код:
TThreadProcedure = reference to procedure;

procedure Synchronize(AThreadProc: TThreadProcedure); overload;

Anonymous methods have many uses and can streamline code (but vice versa). By the way, one of the main goals was support for the future Parallel library, ie better use of multiprocessor systems in future versions.

[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,439
Credits
574
referenced to: