官术网_书友最值得收藏!

Anonymous code

Anonymous code is all about treating code as data. You can assign an implementation of a function or procedure to a variable; you pass functions as parameters to other functions and receive them as results. This is a very powerful feature of the Object Pascal language. With anonymous code, the source code of your app can be more compact and maintainable.

A declaration of an anonymous method type has the following syntax:

type 
  TStringProc = reference to procedure (s: string); 

We are saying that TStringProc is a procedure that takes a string parameter. Now, we can define variables of this string type, assign implementation to them, pass them to functions, or, simply, just call them. Refer to the following code snippet:

procedure CallMe(const proc: TStringProc; msg: string); 
begin 
  proc(msg); 
end; 
 
procedure DoStringProc; 
var 
  proc: TStringProc; 
begin 
 
  proc := procedure(x: string) 
  begin 
    Log('Declared proc got: ' + x); 
  end; 
 
  CallMe(proc, 'Hello'); 
 
  CallMe( 
       procedure(v: string) 
       begin 
         Log('Inline code got: ' + v); 
       end, 
       'World'); 
end; 

Here, we have a CallMe procedure that takes as a parameter a chunk of code compatible with TStringProc and a string variable. There is also a proc local variable of the TStringProc type. In the first lines of the DoStringProc routine, we assign implementation to the proc variable. Note that there is no identifier after the procedure keyword. The parameter declaration follows immediately. This is why it is called anonymous code. It does not need a name because it is never referenced by name. In the first call to CallMe, we pass the proc variable as a parameter. The second call to CallMe is even more compact; we define the implementation of an anonymous procedure, in-place.

A more useful example of using anonymous code could be the sorting of a generic list. We can define the TPersonList class and implement the SortByFullName method:

unit uPersonList; 
 
interface 
 
uses 
  System.Generics.Collections, // TObjectList<T> 
  uPerson;  // TPerson 
 
type 
  TPersonList = class(TObjectList<TPerson>) 
    procedure SortByFullName; 
  end; 
 
implementation 
 
uses 
  System.Generics.Defaults, // IComparer, TComparison 
  System.SysUtils; // CompareStr 
 
 
{ TPersonList } 
 
procedure TPersonList.SortByFullName; 
var 
  Comparer : IComparer<TPerson>; 
  Comparison : TComparison<TPerson>; 
begin 
  Comparison := function(const p1, p2: TPerson): integer 
  begin 
     Result := CompareStr(p1.FullName, p2.FullName); 
  end; 
  Comparer := TComparer<TPerson>.Construct(Comparison); 
  inherited Sort(Comparer); 
end; 
 
end. 

The generic object list class defines the Sort method, which can be overridden in the descendent classes. As its parameter, it expects a generic comparer class, which is only responsible for comparing any two elements of the underlying class; it returns an integer value that needs to be negative if the first element is less than the second, "zero" if they are the same, or a positive value if the first element is greater than the second one. Here, we construct the TComparer class, which is responsible for comparting to TPerson objects. Luckily in the System.SysUtils unit, there is a very handy CompareStr function that we can use directly. Our comparer is referenced by its implementing interface, and that's why we do not need to free it afterwards. It will be freed automatically by the interface reference counting mechanism.

主站蜘蛛池模板: 大名县| 文登市| 祁连县| 格尔木市| 醴陵市| 汶川县| 祁东县| 岳普湖县| 杨浦区| 温宿县| 枝江市| 瑞丽市| 白沙| 迁安市| 邳州市| 宝山区| 诏安县| 上林县| 绥滨县| 五常市| 辽宁省| 太谷县| 吐鲁番市| 嵩明县| 绥江县| 鄱阳县| 青冈县| 甘孜| 凤庆县| 桐城市| 漠河县| 精河县| 洪雅县| 大石桥市| 安徽省| 稻城县| 铁岭县| 阳信县| 加查县| 调兵山市| 海丰县|