|
@@ -0,0 +1,159 @@
|
|
|
+{ %OPT=-gh }
|
|
|
+
|
|
|
+program tw36196;
|
|
|
+
|
|
|
+{$mode objfpc}{$H+}
|
|
|
+{$modeswitch prefixedattributes}
|
|
|
+
|
|
|
+uses
|
|
|
+ {heaptrc, }SysUtils, typinfo, {%H-}rtti;
|
|
|
+
|
|
|
+type
|
|
|
+
|
|
|
+ IntRangeAttribute = class(TCustomAttribute)
|
|
|
+ private
|
|
|
+ FMinValue,
|
|
|
+ FMaxValue: Integer;
|
|
|
+ public
|
|
|
+ constructor Create(aMin, aMax: Integer);
|
|
|
+ property MinValue: Integer read FMinValue;
|
|
|
+ property MaxValue: Integer read FMaxValue;
|
|
|
+ end;
|
|
|
+
|
|
|
+ DefaultStrAttribute = class(TCustomAttribute)
|
|
|
+ private
|
|
|
+ FValue: string;
|
|
|
+ public
|
|
|
+ constructor Create;
|
|
|
+ constructor Create(const aValue: string);
|
|
|
+ property Value: string read FValue;
|
|
|
+ end;
|
|
|
+
|
|
|
+ CheckAttribute = class(TCustomAttribute)
|
|
|
+ private
|
|
|
+ FChecked: Boolean;
|
|
|
+ public
|
|
|
+ constructor Create;
|
|
|
+ constructor Create(aValue: Boolean);
|
|
|
+ property Checked: Boolean read FChecked;
|
|
|
+ end;
|
|
|
+
|
|
|
+ [Check(True)]
|
|
|
+ TMyClass = class
|
|
|
+ private
|
|
|
+ FName,
|
|
|
+ FDescr: string;
|
|
|
+ FId: Integer;
|
|
|
+ published
|
|
|
+ [DefaultStr]
|
|
|
+ property Name: string read FName write FName;
|
|
|
+ [DefaultStr('nice description')]
|
|
|
+ property Description: string read FDescr write FDescr;
|
|
|
+ [IntRange(100, 10000)]
|
|
|
+ property Id: Integer read FId write FId;
|
|
|
+ end;
|
|
|
+
|
|
|
+ [DefaultStr('this is TMyRec')][IntRange(0, 100)]
|
|
|
+ TMyRec = record
|
|
|
+ Name: string;
|
|
|
+ Value: Integer;
|
|
|
+ end;
|
|
|
+
|
|
|
+ [Check][IntRange(-10000, 10000)]
|
|
|
+ TMyInt = type Integer;
|
|
|
+
|
|
|
+{ CheckAttribute }
|
|
|
+
|
|
|
+constructor CheckAttribute.Create;
|
|
|
+begin
|
|
|
+ FChecked := False;
|
|
|
+end;
|
|
|
+
|
|
|
+constructor CheckAttribute.Create(aValue: Boolean);
|
|
|
+begin
|
|
|
+ FChecked := aValue;
|
|
|
+end;
|
|
|
+
|
|
|
+{ DefaultStrAttribute }
|
|
|
+
|
|
|
+constructor DefaultStrAttribute.Create;
|
|
|
+begin
|
|
|
+ FValue := 'Unassigned';
|
|
|
+end;
|
|
|
+
|
|
|
+constructor DefaultStrAttribute.Create(const aValue: string);
|
|
|
+begin
|
|
|
+ FValue := aValue;
|
|
|
+end;
|
|
|
+
|
|
|
+{ TIntRangeAttribute }
|
|
|
+
|
|
|
+constructor IntRangeAttribute.Create(aMin, aMax: Integer);
|
|
|
+begin
|
|
|
+ FMinValue := aMin;
|
|
|
+ FMaxValue := aMax;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure PrintAttribute(Attr: TCustomAttribute);
|
|
|
+begin
|
|
|
+ if not Assigned(Attr) then
|
|
|
+ exit;
|
|
|
+ WriteLn(' Found attribute ', Attr.ClassName, ':');
|
|
|
+ if Attr is DefaultStrAttribute then
|
|
|
+ WriteLn(' property Value has value "', DefaultStrAttribute(Attr).Value, '"')
|
|
|
+ else
|
|
|
+ if Attr is IntRangeAttribute then
|
|
|
+ begin
|
|
|
+ WriteLn(' property MinValue has value ', IntRangeAttribute(Attr).MinValue);
|
|
|
+ WriteLn(' property MaxValue has value ', IntRangeAttribute(Attr).MaxValue);
|
|
|
+ end
|
|
|
+ else
|
|
|
+ if Attr is CheckAttribute then
|
|
|
+ WriteLn(' property Checked has value ', CheckAttribute(Attr).Checked);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure PrintClassAttributes(aClass: TClass);
|
|
|
+var
|
|
|
+ RCtx: TRttiContext;
|
|
|
+ RType: TRttiType;
|
|
|
+ Prop: TRttiProperty;
|
|
|
+ Attr: TCustomAttribute;
|
|
|
+begin
|
|
|
+ RCtx := TRttiContext.Create;
|
|
|
+ try
|
|
|
+ RType := RCtx.GetType(aClass);
|
|
|
+ WriteLn(RType.Name, ' attributes:');
|
|
|
+ for Attr in RType.GetAttributes do
|
|
|
+ PrintAttribute(Attr);
|
|
|
+ for Prop in RType.GetProperties do
|
|
|
+ for Attr in Prop.GetAttributes do
|
|
|
+ PrintAttribute(Attr);
|
|
|
+ finally
|
|
|
+ RCtx.Free;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure PrintTypeAttributes(aInfo: PTypeInfo);
|
|
|
+var
|
|
|
+ RCtx: TRttiContext;
|
|
|
+ RType: TRttiType;
|
|
|
+ Attr: TCustomAttribute;
|
|
|
+begin
|
|
|
+ RCtx := TRttiContext.Create;
|
|
|
+ try
|
|
|
+ RType := RCtx.GetType(aInfo);
|
|
|
+ WriteLn(RType.Name, ' attributes:');
|
|
|
+ for Attr in RType.GetAttributes do
|
|
|
+ PrintAttribute(Attr);
|
|
|
+ finally
|
|
|
+ RCtx.Free;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+begin
|
|
|
+ HaltOnNotReleased:=True;
|
|
|
+ //SetHeapTraceOutput('heap.log');
|
|
|
+ PrintClassAttributes(TMyClass);
|
|
|
+ PrintTypeAttributes(TypeInfo(TMyRec));
|
|
|
+ PrintTypeAttributes(TypeInfo(TMyInt));
|
|
|
+end.
|