Can someone explain Anonymous methods to me?

2019-03-09 17:41发布

Delphi 2009, among some cool stuff, has also just got Anonymous methods. I've seen the examples, and the blog posts regarding anonymous methods, but I don't get them yet. Can someone explain why I should be excited?

7条回答
SAY GOODBYE
2楼-- · 2019-03-09 17:45

Anonymous methods are useful in functional programming, but they also can help you to write a more compact code in structured programming. Threading, for example: http://blogs.codegear.com/abauer/2008/09/08/38868

Another use cases for your 'excitement' :) : http://delphi.fosdal.com/2008/08/anonymous-methods-when-to-use-them.html

查看更多
混吃等死
3楼-- · 2019-03-09 17:48

Just think of typical callback code where you need to have data available to the callback. Often this data is needed for the callback only, yet you have to jump through a number of hoops to get it there without having to resign to un-OOP-friendly practices like global variables. With anonymous methods the data can stay where it is - you don't have to unnecessarily extend its scope or copy it to some helper object. Just write your callback code in-place as an anonymous method and it can fully access and manipulate all local variables at the site where the anonymous method is defined (not where it's called!).

There are other aspects of anonymous methods, most obviously the fact that they are, well: anonymous, but this is the one that really made them go "click" for me...

查看更多
老娘就宠你
4楼-- · 2019-03-09 17:49

I guess (I don't know Delphi) this implies that you can create functions as a kind of data object now. This means that you can, for example, pass functions as parameters to other functions. Example: A sort function might take a comparison function as a parameter, thus being much more versatile.

查看更多
Viruses.
5楼-- · 2019-03-09 17:57

People have already provided the code, so I'll just list some places where they can be useful.

Say you have some GUI code. Normally, for something like a button's onclick handler, you have to provide a function that will be called when that button is clicked. However, let's say all that function has to do is something simple like pop up a message box or set a field somewhere. Let's say you have dozens of these buttons throughout your code. Without anonymous functions, you'll have to have tons of functions called "OnButton1Click," "OnExitButtonClick," etc, which will likely clutter up your code... or you can create anonymous functions that immediately attach to these events, and you don't have to worry about them anymore.

Another use is functional programming. Say you have a list of numbers. You want to get back only those numbers that are divisible by three. There is likely a function called filter which takes a function that returns a boolean and a list, and returns a new list containing only those elements in the first list that, when passed to the function, returned True. Example:

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

It'd be annoying to be forced to define a function "isDivisibleByThree", then pass it to filter, so another use for anonymous functions here would be to just quickly create a function you won't need anywhere else and pass it to filter.

查看更多
劳资没心,怎么记你
6楼-- · 2019-03-09 18:02

I'm answering my own question, but I found a good explanation of anonymous methods here Can your programming language do this?

查看更多
姐就是有狂的资本
7楼-- · 2019-03-09 18:07

May be this example can be of some value for you. Here I'm going to implement a zoomable display list for drawing on a TCanvas without declaring different types of display classes. It also makes heavy use of Generics. Assume we have a TForm with a TPaintBox and a TTrackBar on it...

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;
查看更多
登录 后发表回答