¿Puede alguien explicarme métodos anónimos?


Delphi 2009, entre algunas cosas interesantes, también tiene métodos anónimos. He visto los ejemplos y las publicaciones de blog sobre métodos anónimos, pero aún no los entiendo. ¿Alguien puede explicar por qué debería estar emocionado?

Author: Toon Krijthe, 2008-11-02

7 answers

Solo piense en el típico código de devolución de llamada donde necesita tener datos disponibles para la devolución de llamada. A menudo estos datos son necesarios para la devolución de llamada solo, sin embargo, tienes que saltar a través de una serie de aros para llegar allí sin tener que renunciar a las prácticas no-OOP-friendly como variables globales. Con métodos anónimos, los datos pueden permanecer donde están, no tiene que extender innecesariamente su alcance o copiarlos en algún objeto auxiliar. Simplemente escriba su código de devolución de llamada en el lugar como un método anónimo y puede acceder y manipular completamente todas las variables locales en el sitio donde se define el método anónimo (¡no donde se llama!).

Hay otros aspectos de los métodos anónimos, lo más obvio es el hecho de que son, bueno: anónimos, pero este es el que realmente los hizo hacer "clic" para mí...

 11
Author: Oliver Giesen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-05 14:00:44

Por favor, echa un vistazo a cierres.

Las funciones anónimas de Delphi son cierres.

Estos se crean dentro de otras funciones y como tales tiene acceso al alcance de esa función. Esto es aún así si la función anónima se asigna a un parámetro de función que se llama después de que se llama a la función original. (Crearé un ejemplo en un momento).

type
  TAnonFunc = reference to procedure;
  TForm2 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    F1 : TAnonFunc;
    F2 : TAnonFunc;
  end;

procedure TForm2.Button1Click(Sender: TObject);
var
  a : Integer;
begin
  a := 1;

  F1 := procedure
  begin
    a := a + 1;
  end;

  F2 := procedure
  begin
    Memo1.Lines.Add(IntToStr(a));
  end;
end;

El método anterior asigna dos funciones anónimas a los campos F1 y F2. El primero aumenta la variable local y la segunda muestra el valor de la variable.

procedure TForm2.Button2Click(Sender: TObject);
begin
  F1;
end;

procedure TForm2.Button3Click(Sender: TObject);
begin
  F2;
end;

Ahora puede llamar a ambas funciones, y acceden a la misma a. Así que llamar a F1 dos veces y a F2 una vez muestra un 3. Por supuesto, este es un ejemplo simple. Pero se puede ampliar a código más útil.

En el entorno multi threading, se pueden usar funciones anónimas en una llamada para Sincronizar, lo que elimina la necesidad de innumerables métodos.

 15
Author: Toon Krijthe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-01 22:11:13

Puede ser este ejemplo puede ser de algún valor para usted. Aquí voy a implementar una lista de visualización ampliable para dibujar en un TCanvas sin declarar diferentes tipos de clases de visualización. También hace un uso intensivo de genéricos. Supongamos que tenemos un TForm con un TPaintBox y una TTrackBar en él...

type
  TDisplayProc = TProc<TCanvas>;

type
  TFrmExample3 = class(TForm)
    pbxMain: TPaintBox;
    trkZoom: TTrackBar;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure pbxMainClick(Sender: TObject);
    procedure pbxMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure pbxMainPaint(Sender: TObject);
    procedure trkZoomChange(Sender: TObject);
  private
    FDisplayList: TList<TDisplayProc>;
    FMouseX: Integer;
    FMouseY: Integer;
    FZoom: Extended;
    procedure SetZoom(const Value: Extended);
  protected
    procedure CreateCircle(X, Y: Integer);
    procedure CreateRectangle(X, Y: Integer);
    function MakeRect(X, Y, R: Integer): TRect;
  public
    property Zoom: Extended read FZoom write SetZoom;
  end;

implementation

{$R *.dfm}

procedure TFrmExample3.PaintBox1Paint(Sender: TObject);
var
  displayProc: TDisplayProc;
begin
  for displayProc in FDisplayList do
    displayProc((Sender as TPaintBox).Canvas);
end;

procedure TFrmExample3.CreateCircle(X, Y: Integer);
begin
  FDisplayList.Add(
    procedure (Canvas: TCanvas)
    begin
      Canvas.Brush.Color := clYellow;
      Canvas.Ellipse(MakeRect(X, Y, 20));
    end
  );
end;

procedure TFrmExample3.CreateRectangle(X, Y: Integer);
begin
  FDisplayList.Add(
    procedure (Canvas: TCanvas)
    begin
      Canvas.Brush.Color := clBlue;
      Canvas.FillRect(MakeRect(X, Y, 20));
    end
  );
end;

procedure TFrmExample3.FormCreate(Sender: TObject);
begin
  FDisplayList := TList<TDisplayProc>.Create;
end;

procedure TFrmExample3.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FDisplayList);
end;

function TFrmExample3.MakeRect(X, Y, R: Integer): TRect;
begin
  Result := Rect(Round(Zoom*(X - R)), Round(Zoom*(Y - R)), Round(Zoom*(X + R)), Round(Zoom*(Y + R)));
end;

procedure TFrmExample3.pbxMainClick(Sender: TObject);
begin
  case Random(2) of
    0: CreateRectangle(Round(FMouseX/Zoom), Round(FMouseY/Zoom));
    1: CreateCircle(Round(FMouseX/Zoom), Round(FMouseY/Zoom));
  end;
  pbxMain.Invalidate;
end;

procedure TFrmExample3.pbxMainMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  FMouseX := X;
  FMouseY := Y;
end;

procedure TFrmExample4.SetZoom(const Value: Extended);
begin
  FZoom := Value;
  trkZoom.Position := Round(2*(FZoom - 1));
end;

procedure TFrmExample4.trkZoomChange(Sender: TObject);
begin
  Zoom := 0.5*(Sender as TTrackBar).Position + 1;
  pbxMain.Invalidate;
end;
 11
Author: Uwe Raabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-02 18:13:35

La gente ya ha proporcionado el código, así que solo enumeraré algunos lugares donde pueden ser útiles.

Digamos que tienes algún código GUI. Normalmente, para algo como el controlador onclick de un botón, debes proporcionar una función a la que se llamará cuando se haga clic en ese botón. Sin embargo, digamos que todo lo que la función tiene que hacer es algo simple como abrir un cuadro de mensaje o establecer un campo en algún lugar. Digamos que tienes docenas de estos botones a lo largo de tu código. Sin funciones anónimas, tiene que tener toneladas de funciones llamadas " OnButton1Click," "OnExitButtonClick," etc, que probablemente desordenará su código... o puede crear funciones anónimas que se adjuntan inmediatamente a estos eventos, y ya no tiene que preocuparse por ellos.

Otro uso es la programación funcional. Digamos que tienes una lista de números. Usted quiere recuperar sólo los números que son divisibles por tres. Probablemente hay una función llamada filter que toma una función que devuelve un booleano y un list, y devuelve una nueva lista que contiene solo los elementos de la primera lista que, cuando se pasan a la función, devuelven True. Ejemplo:

filter(isOdd, [1, 2, 3, 5, 6, 9, 10]) --> [1, 3, 5, 9]

Sería molesto ser forzado a definir una función "isDivisibleByThree", luego pasarla a filter, por lo que otro uso para funciones anónimas aquí sería simplemente crear rápidamente una función que no necesitará en ningún otro lugar y pasarla a filter.

 5
Author: Claudiu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-02 18:24:39

Estoy respondiendo a mi propia pregunta, pero encontré una buena explicación de los métodos anónimos aquí ¿Puede su lenguaje de programación hacer esto?

 5
Author: Steve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-02 23:18:40

Supongo (no conozco Delphi) esto implica que ahora puedes crear funciones como una especie de objeto de datos. Esto significa que puede, por ejemplo, pasar funciones como parámetros a otras funciones. Ejemplo: Una función de ordenación puede tomar una función de comparación como parámetro, por lo que es mucho más versátil.

 1
Author: Svante,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-01 21:48:58

Los métodos anónimos son útiles en la programación funcional, pero también pueden ayudarle a escribir un código más compacto en la programación estructurada. Roscado, por ejemplo: http://blogs.codegear.com/abauer/2008/09/08/38868

Otros casos de uso para su' emoción':): http://delphi.fosdal.com/2008/08/anonymous-methods-when-to-use-them.html

 1
Author: F.D.Castel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-02 08:02:19