RTTi (RunTime Type Information - thông tin loại thời gian chạy) là thông tin về một loại (kiểu dữ liệu) có thể thu được trong thời gian chạy.
Attributes (thuộc tính - cần phân biệt với property của OOP) là các thuộc tính của một loại được nạp vào khi khai báo, có thể sử dụng khi chạy để truy vấn.
Bản chất của Attributes là một class con của lớp TCustomAttribute, lớp này được gán vào một đối tượng (lớp khác, kiểu dữ liệu) và được nạp khi đối tượng được gán khởi động.
type
TXeHoiInfo = class(TCustomAttribute)
FTenXe: string;
FNamSanXuat: Word;
constructor Create(NhaSX: string; NamSX: Word);
end;
Đoạn code trên khai báo một lớp attributes TXeHoiInfo, lưu trữ thông tin Tên xe và năm sản xuất, được nạp vào bằng ghi đè phương thức khởi tạo Create.
Phương thức Create tùy chỉnh là bắt buộc để sử dụng được Attribute.
Lấy ví dụ trên, ta triển khai lớp attribute TXeHoiInfo (triển khai phương thức Create)
constructor TXeHoiInfo.Create(TenXe: string; NamSX: Word);
begin
FTenXe := TenXe;
FNamSanXuat := NamSX;
end;
Đối với các lớp bình thường, cần thực thể hóa (instantiation) lớp thành object sau đó mới sử dụng được thông qua object vừa khởi tạo.
Lớp attribute không phải khởi tạo như thế, nó sẽ không tạo ra object, nó được tạo ra khi đối tượng chủ (được gán) được tạo ra.
Sau khi khai báo lớp attribute và triển khai phương thức Create, cần phải gán nó cho một đối tượng khác.
type
[ TXeHoiInfo('Taxi Mai Linh', 2018) ]
TTaxiMaiLinh = class
FChuXe: string;
procedure RunTo(DiaDiem: string);
end;
Như trên, chúng ta tạo ra một lớp TTaxiMaiLinh, gồm một trường Chủ xe và phương thức RunTo để đi đến một địa điểm nào đó.
Lớp TTaxiMaiLinh được gán một attribute TXeHoiInfo với các thông tin Taxi Mai Linh (tên xe), 2018 (năm SX).
Bây giờ là lúc attribute phát huy tác dụng của nó: Lớp TTaxiMaiLinh dù được sử dụng vẫn không biết chính nó tên là gì (Taxi Mai Linh). Nếu khách hàng hỏi anh lái xe cho hãng nào, nếu không có attribute thì class TTaxiMaiLinh không thể biết được.
Một lớp được gán attribute có thể biết được thông tin của chính nó. Như lớp TTaxiMaiLinh khi được gán attribute có thể biết được chính nó là Taxi Mai Linh, và xe của nó được sản xuất năm 2018.
Đó là tác dụng của attribute trong thực tế. Thực tế, ít khi người ta sử dụng attribute trong lập trình OOP. Attribute là một phần của lập trình khía cạnh (POP) trong tương lai.
Để trích xuất attribute trong thời gian chạy, ta cần 3 lớp:
var
LContext: TRttiContext;
LType: TRttiType;
LAttr: TRttiAttribute;
...
begin
LContext := TRttiContext.Create;
LType := LContext.GetType(TypeInfo(TTaxiMaiLinh));
for LAttri in TType.GetAttribute do
if LAttr is TInfoXeHoi then
begin
WriteLn((LAttr as TInfoXeHoi).FChuXe);
WriteLn((LAttr as TInfoXeHoi).FNamSanXuat);
end;
LContext.Free;
end.
Cách hoạt động:
Lưu ý: