Подтвердить что ты не робот

Может ли кто-нибудь объяснить мне анонимные методы?

Delphi 2009, среди некоторых классных вещей, также просто получил анонимные методы. Я видел примеры и сообщения в блогах об анонимных методах, но я их пока не получаю. Может кто-нибудь объяснить, почему я должен быть взволнован?

4b9b3361

Ответ 1

Подумайте о типичном коде обратного вызова, где вам нужно иметь данные для обратного вызова. Часто эти данные необходимы для обратного вызова только, но вам нужно перепрыгнуть через ряд обручей, чтобы получить их там, не откладывая на непригодные для OOP методы, такие как глобальные переменные. С помощью анонимных методов данные могут оставаться там, где они есть - вам не нужно излишне расширять область действия или копировать ее на какой-либо вспомогательный объект. Просто напишите свой код обратного вызова на месте как анонимный метод, и он может полностью получить доступ и управлять всеми локальными переменными на сайте, где определен анонимный метод (не там, где он звонил!).

Существуют и другие аспекты анонимных методов, наиболее очевидно, что они есть, ну: анонимно, но это тот, который действительно заставил их пойти "click" для меня...

Ответ 2

Пожалуйста, посмотрите закрытия.

Анонимные функции Delphi - это закрытие.

Они создаются в рамках других функций и, таким образом, имеют доступ к области действия этой функции. Это даже так, если анонимной функции присваивается параметр функции, вызываемый после вызова исходной функции. (Я создам пример в одно мгновение).

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;

Вышеуказанный метод присваивает двум анонимным функциям поля F1 и F2. Первая увеличивает локальную переменную, а вторая показывает значение переменной.

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

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

Теперь вы можете вызывать обе функции, и они получают доступ к тем же а. Поэтому дважды вызывайте F1, а F2 показывает 3. Конечно, это простой пример. Но он может быть расширен до более полезного кода.

В многопоточной среде анонимные функции могут использоваться в вызове Synchronize, что устраняет необходимость в бесчисленных методах.

Ответ 3

Может быть, этот пример может иметь для вас какое-то значение. Здесь я собираюсь реализовать масштабируемый список отображения для рисования на TCanvas без объявления различных типов классов отображения. Он также активно использует дженерики. Предположим, что у нас есть TForm с TPaintBox и TTrackBar на нем...

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;

Ответ 4

Люди уже предоставили код, поэтому я просто перечислил некоторые места, где они могут быть полезны.

Скажем, у вас есть код GUI. Обычно, для чего-то вроде кнопки onclick handler, вы должны предоставить функцию, которая будет вызываться при нажатии этой кнопки. Однако позвольте сказать, что все, что нужно сделать, - это что-то простое, как всплывающее окно сообщения или где-то установить поле. Скажем, у вас есть десятки этих кнопок на вашем коде. Без анонимных функций вам нужно будет иметь множество функций, называемых "OnButton1Click", "OnExitButtonClick" и т.д., Которые, вероятно, загромождают ваш код... или вы можете создавать анонимные функции, которые немедленно присоединяются к этим событиям, и вы больше не о чем беспокоиться.

Еще одно использование - функциональное программирование. Скажем, у вас есть список номеров. Вы хотите вернуть только те числа, которые делятся на три. Вероятно, существует функция под названием filter, которая принимает функцию, которая возвращает логическое значение и список, и возвращает новый список, содержащий только те элементы в первом списке, которые при передаче функции возвращают значение True. Пример:

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

Было бы очень сложно определить функцию isDivisibleByThree, а затем передать ее для фильтрации, поэтому другое использование для анонимных функций здесь - это просто создать функцию, которая вам больше не понадобится и передать ее для фильтрации.

Ответ 6

Я предполагаю (я не знаю Delphi), это означает, что теперь вы можете создавать функции как своего рода объект данных. Это означает, что вы можете, например, передавать функции в качестве параметров для других функций. Пример. Функция сортировки может использовать функцию сравнения в качестве параметра, тем самым более универсальную.

Ответ 7

Анонимные методы полезны в функциональном программировании, но они также могут помочь вам написать более компактный код в структурированном программировании. Threading, например: http://blogs.codegear.com/abauer/2008/09/08/38868

Другие варианты использования для вашего "волнения":): http://delphi.fosdal.com/2008/08/anonymous-methods-when-to-use-them.html