问题
Why are some properties repeated (such as Action
and Align
) where others are not (AlignWithMargins
) when TRttiContext.GetType is called on a VCL Control?
uses
System.RTTI,
System.Generics.Collections,
System.Generics.Defaults;
//....
procedure TForm11.btnShowPropertiesClick(Sender: TObject);
var
R: TRttiContext;
Props: TArray<TRttiProperty>;
Prop : TRttiProperty;
begin
memo1.Clear;
R := TRttiContext.Create;
Props := R.GetType(Sender.ClassType).GetProperties;
//Sort properties by name
TArray.Sort<TRttiProperty>(props,
TComparer<TRttiProperty>.Construct(
function(const Left, Right: TRttiProperty): Integer
begin
result := CompareText(Left.Name, Right.Name);
end
)
);
for prop in Props do
begin
try
Memo1.Lines.Add(
Prop.Name + ' : ' +
Prop.PropertyType.ToString + ' = ' +
Prop.GetValue(Sender).ToString);
except
Memo1.Lines.Add(Prop.Name + ' generated an exception');
end;
end;
end;
Output
Action : TBasicAction = (empty) Action : TBasicAction = (empty) Align : TAlign = alNone Align : TAlign = alNone AlignDisabled : Boolean = False AlignWithMargins : Boolean = False Anchors : TAnchors = [akLeft,akTop] Anchors : TAnchors = [akLeft,akTop] BiDiMode : TBiDiMode = bdLeftToRight BiDiMode : TBiDiMode = bdLeftToRight ...
回答1:
If you would add Prop.Parent.Name
to the loop that populates the memo you could have easily found out the cause:
for prop in Props do
begin
try
Memo1.Lines.Add(
Prop.Parent.Name + '.' + { added }
Prop.Name + ' : ' +
Prop.PropertyType.ToString + ' = ' +
Prop.GetValue(Sender).ToString);
except
Memo1.Lines.Add(Prop.Name + ' generated an exception');
end;
end;
The code above produces:
TButton.Action : TBasicAction = (empty)
TControl.Action : TBasicAction = (empty)
TControl.Align : TAlign = alNone
TButton.Align : TAlign = alNone
TWinControl.AlignDisabled : Boolean = False
TControl.AlignWithMargins : Boolean = False
TControl.Anchors : TAnchors = [akLeft,akTop]
TButton.Anchors : TAnchors = [akLeft,akTop]
TButton.BiDiMode : TBiDiMode = bdLeftToRight
TControl.BiDiMode : TBiDiMode = bdLeftToRight
...
Now you can clearly see that that GetProperties enumerates properties that were reintroduced in descendant class with higher visibility or altered order. This is typical for controls when TCustomMyControl
defines SomeProperty
with protected
visibility and TMyControl
reintroduces it at published
level.
You can try adding interposer class for TButton
before the TForm11
declaration:
type
TButton = class(Vcl.StdCtrls.TButton)
published
property AlignWithMargins;
end;
The output would reflect the change. I added fully qualified name of property's declaring type (Prop.Parent.QualifiedName
) to make it more obvious that TButton
comes from my own unit.
Vcl.StdCtrls.TButton.Action : TBasicAction = (empty)
Vcl.Controls.TControl.Action : TBasicAction = (empty)
Vcl.Controls.TControl.Align : TAlign = alNone
Vcl.StdCtrls.TButton.Align : TAlign = alNone
Vcl.Controls.TWinControl.AlignDisabled : Boolean = False
Vcl.Controls.TControl.AlignWithMargins : Boolean = False
Unit1.TButton.AlignWithMargins : Boolean = False
Vcl.Controls.TControl.Anchors : TAnchors = [akLeft,akTop]
Vcl.StdCtrls.TButton.Anchors : TAnchors = [akLeft,akTop]
Vcl.StdCtrls.TButton.BiDiMode : TBiDiMode = bdLeftToRight
Vcl.Controls.TControl.BiDiMode : TBiDiMode = bdLeftToRight
...
This kind of behavior is not limited to controls. It can be observed on any class that reintroduces properties from an ancestor class.
回答2:
Would GetDeclaredProperties() be more useful?
The help states that the difference between GetDeclaredProperties() and GetProperties() is:
Use the GetDeclaredProperties method to obtain a list of all the properties that are declared in the reflected type. To obtain the list of all properties in the reflected type (including the inherited ones), use the GetProperties method instead.
Therefore I would think in your case GetProperties() is working as designed, and returning both properties and inherited properties - hence why some properties are appearing more than once.
来源:https://stackoverflow.com/questions/63983114/why-are-some-properties-repeated-when-trtticontext-gettype-is-called-on-a-vcl-co