6

为什么在 VCL 控件上调用 TRttiContext.GetType 时,某些属性会重复(例如ActionAlign)而其他属性不会( )?AlignWithMargins

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;

输出

动作:TBasicAction =(空)
动作:TBasicAction =(空)
对齐:TAlign = alNone
对齐:TAlign = alNone
AlignDisabled : Boolean = False
AlignWithMargins : Boolean = False
锚点:TAnchors = [akLeft,akTop]
锚点:TAnchors = [akLeft,akTop]
BiDiMode:TBiDiMode = bdLeftToRight
BiDiMode:TBiDiMode = bdLeftToRight
...
4

2 回答 2

9

如果您要添加Prop.Parent.Name到填充备忘录的循环中,您可以很容易地找出原因:

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;

上面的代码产生:

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
...

现在您可以清楚地看到,它GetProperties枚举了在具有更高可见性或更改顺序的后代类中重新引入的属性。这对于具有可见性TCustomMyControl定义并在级别重新引入它的控件来说是典型的。SomePropertyprotectedTMyControlpublished

您可以尝试在声明TButton之前添加 interposer 类:TForm11

type
  TButton = class(Vcl.StdCtrls.TButton)
  published
    property AlignWithMargins;
  end;

输出将反映变化。我添加了属性声明类型 ( ) 的完全限定名称,Prop.Parent.QualifiedName以使其更明显TButton来自我自己的单元。

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。锚点:TAnchors = [akLeft,akTop]
Vcl.StdCtrls.TButton.BiDiMode:TBiDiMode = bdLeftToRight
Vcl.Controls.TControl.BiDiMode:TBiDiMode = bdLeftToRight
...

这种行为不仅限于控件。它可以在任何重新引入祖先类属性的类上观察到。

于 2020-09-20T20:58:23.653 回答
5

GetDeclaredProperties() 会更有用吗?

帮助指出 GetDeclaredProperties() 和 GetProperties() 之间的区别是:

使用GetDeclaredProperties方法获取在反射类型中声明的所有属性的列表。要获取反射类型中所有属性的列表(包括继承的属性),请改用 GetProperties 方法。

因此,我认为在您的情况下 GetProperties() 正在按设计工作,并返回属性和继承的属性 - 因此为什么某些属性会出现不止一次。

于 2020-09-21T00:08:44.263 回答