Anonymous Methods
Phương thức ẩn danh
Phương thức ẩn danh
Như cái tên, phương thức ẩn danh có nghĩa là một phương thức (hàm, thủ tục) không có tên. Anonymous methods có thể gán vào một biến có cùng kiểu.
Ưu điểm của anonymous methods là có thể khai báo một hàm, thủ tục ở bất cứ nơi đâu trong chương trình, như ví dụ sau
type
TFuncSum = reference to function (Num1, Num2: Integer): Integer;
...
var
Sum: TFuncSum;
begin
Sum := function (Num1, Num2: Integer): Integer
begin
Result := Num1 + Num2;
end;
Write(Sum(10, 20)); // 10 + 20 = 30
end.
Delegate là một kiểu tham chiếu (reference to) đến hàm, thủ tục, phương thức.
Mỗi delegate đặc trưng cho cấu trúc một hàm, thủ tục hay phương thức, được xác định bằng 3 điều kiện:
Integer, Interger, String
hoặc Char, Integer
hoặc rỗng ()
type
TProcedure = reference to procedure;
TSumFunction = reference to function (a, b: Integer);
Các phương thức ẩn danh (phần sau) có cùng delegate thì có thể gán qua lại cho nhau.
type
TFuncSum = reference to function (Num1, Num2: Integer): Integer;
...
var
Sum: TFuncSum;
Sum2: TFuncSum;
begin
Sum := function (Num1, Num2: Integer): Integer
begin
Result := Num1 + Num2;
end;
Write(Sum(10, 20)); // 10 + 20 = 30
Sum2 := Sum;
Write(Sum2(1, 2)); // 1 + 2 = 3
end.
Ta thêm một biến cùng kiểu với Sum. Do hai hàm ẩn danh này có cùng kiểu (giống nhau) nên chúng có thể gán qua lại cho nhau.
Khác với các hàm, thủ tục thông thường được triển khai bên ngoài khối, hàm ẩn danh cho phép gán ngay trong một khối begin end như các ví dụ trên.
Thêm nữa, các hàm ẩn danh có thể là đối số của một hàm khác. Xem ví dụ
type
TProcWriteString = reference to procedure (Str: string);
...
procedure RunAProc(Proc: TProcWriteString);
begin
WriteLn('Running ... ');
Proc;
WriteLn('Run complete');
end;
...
var
MyProc: TProcWriteString;
begin
MyProc := procedure (Str: string)
begin
Write(Str);
end;
RunAProc(MyProc);
end.
Như trên, ta khai báo một hàm ẩn danh (thủ tục ẩn danh) tên MyProc kiểu TProcWriteString. Sau đó triển khai nội dung cho nó bên trong cặp begin end chính.
Ta tạo thêm một hàm RunAProc (Run a procedure), nhận tham số là một biến của TProcWriteString để thực hiện.
type
TFunc = reference to function (x: Integer): Integer;
type
TClass = class
function Cong1 (x: Integer): Integer;
end;
...
var
Func: TFunc;
Obj: TClass;
begin
Obj := TClass.Create;
Func := Obj.Cong1;
Write(Func(3)); // 3 + 1 = 4
Obj.Free;
end.
Lưu ý, ta chỉ có thể gán hàm ẩn danh cho phương thức đã được thể hiện của một class, chứ không thể gán trực tiếp cho class chưa khởi tạo.
Có nghĩa là ta cần phải thể hiện một Obj là thể hiện của Class (dùng Create như ví dụ trên). Sau đó gán Func := Obj.Cong1
Dễ thấy đoạn code sau là sai
Func := TClass.Cong1;
Và phải nhớ Free object sau khi dùng xong để tránh lãng phí bộ nhớ.
Delegate có thể tạm dịch là con trỏ hàm, nó trỏ đến một hàm một thủ tục tương tự phương thức ẩn danh nhưng có những điểm khác biệt sau:
Khai báo một delegate
type
TMyDelegate1 = procedure of object;
TMyDelegate2 = procedure (s: string) of object;
TMyDelegate3 = function : Integer of object;
TMyDelegate4 = function (a, b: Integer): Boolean of object;
Như trên mình khai báo 4 dạng của delegate, gồm hai loại là delegate trỏ đến thủ tục (dạng 1, 2) và trỏ đến hàm (dạng 3, 4).
Cấu trúc khai báo chung của một delegate tương tự như anonymous function nhưng không có reference of ở đầu mà thay bằng of object ở cuối.
Delegate sử dụng tương tự như phương thức ẩn danh, nhưng chỉ gán được cho method của class và không thể khởi tạo trực tiếp.