Domanda

Delphi 2009, tra alcune cose interessanti, ha anche ottenuto metodi anonimi. Ho visto gli esempi e i post sul blog riguardanti metodi anonimi, ma non li ho ancora. Qualcuno può spiegare perché dovrei essere eccitato?

È stato utile?

Soluzione

Basti pensare al tipico codice di callback in cui è necessario disporre dei dati disponibili per il callback. Spesso questi dati sono necessari per il callback solo , tuttavia è necessario passare attraverso una serie di cerchi per arrivarci senza dover rinunciare a pratiche non-OOP come le variabili globali. Con metodi anonimi i dati possono rimanere dove sono: non è necessario estenderne inutilmente l'ambito o copiarli in qualche oggetto helper. Basta scrivere il codice di callback sul posto come metodo anonimo e può accedere e manipolare completamente tutte le variabili locali sul sito in cui è definito il metodo anonimo (non dove viene chiamato!).

Ci sono altri aspetti dei metodi anonimi, più ovviamente il fatto che siano, beh: anonimi, ma questo è quello che li ha fatti andare davvero " click " per me ...

Altri suggerimenti

Dai un'occhiata a chiusure .

Le funzioni anonime di Delphi sono chiusure.

Questi sono creati all'interno di altre funzioni e come tali hanno accesso all'ambito di quella funzione. Ciò accade anche se la funzione anonima è assegnata a un parametro di funzione chiamato dopo che è stata chiamata la funzione originale. (Creerò un esempio tra 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;

Il metodo sopra riportato assegna due funzioni anonime ai campi F1 e F2. Il primo aumenta la variabile locale e il secondo mostra il valore della variabile.

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

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

Ora puoi chiamare entrambe le funzioni e accedono alle stesse a. Quindi chiamare F1 due volte e F2 una volta mostra un 3. Naturalmente questo è un semplice esempio. Ma può essere esteso a un codice più utile.

Nell'ambiente multi threading, è possibile utilizzare funzioni anonime in una chiamata a Synchronize, che elimina la necessità di innumerevoli metodi.

Può essere questo esempio può essere di qualche valore per te. Qui ho intenzione di implementare un elenco di visualizzazione zoomabile per disegnare su un TCanvas senza dichiarare diversi tipi di classi di visualizzazione. Fa anche un forte uso di Generics. Supponiamo di avere un TForm con un TPaintBox e un TTrackBar su di esso ...

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;

Le persone hanno già fornito il codice, quindi elencherò solo alcuni luoghi in cui possono essere utili.

Supponi di avere del codice GUI. Normalmente, per qualcosa come il gestore onclick di un pulsante, è necessario fornire una funzione che verrà chiamata quando si fa clic su quel pulsante. Tuttavia, supponiamo che tutto ciò che questa funzione debba fare sia qualcosa di semplice come aprire una finestra di messaggio o impostare un campo da qualche parte. Supponiamo che tu abbia dozzine di questi pulsanti in tutto il codice. Senza funzioni anonime, dovrai avere tonnellate di funzioni chiamate " OnButton1Click, " & Quot; OnExitButtonClick, " ecc., che probabilmente ingombreranno il tuo codice ... o puoi creare funzioni anonime che si collegano immediatamente a questi eventi e non devi più preoccuparti di loro.

Un altro uso è la programmazione funzionale. Supponi di avere un elenco di numeri. Vuoi recuperare solo quei numeri che sono divisibili per tre. Probabilmente esiste una funzione chiamata filter che accetta una funzione che restituisce un valore booleano e un elenco e restituisce un nuovo elenco contenente solo quegli elementi nel primo elenco che, quando passati alla funzione, hanno restituito True. Esempio:

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

Sarebbe fastidioso essere costretto a definire una funzione "isDivisibleByThree", quindi passarla al filtro, quindi un altro uso delle funzioni anonime qui sarebbe quello di creare rapidamente una funzione che non ti servirà da nessun'altra parte e passare per filtrare.

Sto rispondendo alla mia domanda, ma ho trovato una buona spiegazione dei metodi anonimi qui Il tuo linguaggio di programmazione può farlo?

Immagino (non conosco Delphi) questo implica che ora puoi creare funzioni come una specie di oggetto dati. Ciò significa che, ad esempio, è possibile passare funzioni come parametri ad altre funzioni. Esempio: una funzione di ordinamento potrebbe assumere una funzione di confronto come parametro, essendo quindi molto più versatile.

I metodi anonimi sono utili nella programmazione funzionale, ma possono anche aiutarti a scrivere un codice più compatto nella programmazione strutturata. Threading, ad esempio: http://blogs.codegear.com/abauer/2008 / 09/08/38868

Un altro caso d'uso per la tua "emozione" :): http://delphi.fosdal.com/2008/08/anonymous-methods-when-to-use-them.html

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top