Barry Kelly has explained in his recent post how to obtain a method pointer from an anonymous method. Here I will play a little more with the anonymous methods (using Delphi 2009) and consider a somewhat reversed problem – how to create an anonymous method that incapsulates the ordinary function.
First how it is done in the “normal” way:
type TIntFunc = function(Value: Integer): Integer; TIntFuncRef = reference to function(Value: Integer): Integer; function Square(Value: Integer): Integer; begin Result:= Value * Value; end; function MakeAnonMethod(AFunc: TIntFunc): TIntFuncRef; begin Result:= function(Value: Integer): Integer begin Result:= AFunc(Value); end; end; procedure TForm1.Button1Click(Sender: TObject); var AnonMethod: TIntFuncRef; begin AnonMethod:= MakeAnonMethod(@Square); ShowMessage(IntToStr(AnonMethod(2))); end;
The MakeAnonMethod function creates the anonymous method that captures a function variable (AFunc argument, actually a pointer). That is simple.
Now let us consider what is going on behind the scene. An anonymous method is internally an interface with a single method “Invoke”:
type TAnonCaller = class(TInterfacedObject, TIntFuncRef) private FFunc: TIntFunc; function Invoke(Value: Integer): Integer; public constructor Create(AFunc: TIntFunc); end; constructor TAnonCaller.Create(AFunc: TIntFunc); begin FFunc:= AFunc; end; function TAnonCaller.Invoke(Value: Integer): Integer; begin Result:= FFunc(Value); end; procedure TForm1.Button2Click(Sender: TObject); var AnonMethod: TIntFuncRef; begin AnonMethod:= TAnonCaller.Create(@Square); ShowMessage(IntToStr(AnonMethod(2))); end;
The second code snippet do the same thing as the first – it “captures” the function variable in TAnonCaller.Create constructor and uses it to call the “captured” function.
The above code snippets show that
- when we create an anonymous method we actually create an object that implements an interface of a special kind and obtain a reference to the interface
- when we call the anonymous method we actually call the Invoke method of the interface.
The above is an oversimplified description of how the anonymous methods work internally. A more closer look at anonymous methods shows that several anonymous methods may share a single object implementing the interfaces for all of them, and that is the way how the different anonymous methods share the captured variables (as fields of the common object).