I know by TMS Aurelius that we can use the \"new\" 2010 attributes feature to serialize database table fields into object properties at run-time, for example, and I am not an ex
If you want to declare you own attribute, you can do it like this:
type
TDisplayLabelAttribute = class(TCustomAttribute)
private
FText: string;
public
constructor Create(const aText: string);
property Text: string read FText write FText;
end;
An attribute is a regular class, that has the TCustomAttribute as its ancestor. You implement it as usual:
implementation
constructor TDisplayLabelAttribute.Create(const aText: string);
begin
FText := aText;
end;
Now the attribute is declared and implemented, you can just use it:
[DisplayLabel('My Class')]
TMyClass = class
end;
So now you have an attribute declared and implemented and you have used it to add a display label to some class. The final phase is to use that attribute, since you have a class decorated with it. The code that uses the attribute does not resides in the attribute nor the decorated class, it is implemented in the service layer that will use the decoration.
Let's say we have a class that returns a possible display label for a class:
type
TArtifactInspector = class
public
class function DisplayLabelFor(aClass: TClass): string;
end;
That method will inspect a class and return its display label, given it exists. Otherwise it returns an empty string:
implementation
uses
Rtti;
class function TArtifactInspector.DisplayLabelFor(aClass: TClass): string;
var
rttiContext: TRttiContext;
rttiType: TRttiType;
attribute: TCustomAttribute;
begin
rttiContext := TRttiContext.Create;
try
rttiType := rttiContext.GetType(aClass);
for attribute in rttiType.GetAttributes do
if attribute is TDisplayLabelAttribute then
Exit(TDisplayLabelAttribute(attribute).Text);
Result := '';
finally
rttiContext.Free;
end; // try to recover and return the DisplayLabel
end;