RTTI:如何获取字段的对象指针?

RTTI: how to get the object pointer of a field?

我有一个名为 aRttiPropertyTRttiProperty 变量,它指向下面的 属性:

Tsubscription = class(TMyObject)
private
  fBilling: TMyObject;
public
  property billing: TMyObject read fBilling; // << aRttiProperty point to this member
end;

现在,如何从 aRttiProperty 中提取 fBilling 对象指针?

我尝试这样做,但它不起作用:

function Tsubscription.getfBillingObj(const aRttiProperty: TRttiProperty): TMyObject 
begin
  Result := aRttiProperty.GetValue(Self).AsType<TMyObject>;
end; 

它返回父 TSubscription 对象而不是 fbilling 字段对象。

您在问题中显示的代码非常好(前提是您修改了 Tsubscription class 声明以包含 getfBillingObj() 方法)。您显示 returns 正确对象指针的 getfBillingObj() 代码,如以下代码所示:

uses
  System.Rtti;

type
  TMyObject = class
  public
    Name: string;
    constructor Create(const aName: string);
  end;

  Tsubscription = class(TMyObject)
  private
    fBilling: TMyObject;
  public
    constructor Create(const aName: string);
    destructor Destroy; override;
    function getfBillingObj(const aRttiProperty: TRttiProperty): TMyObject;
    property billing: TMyObject read fBilling;
  end;

constructor TMyObject.Create(const aName: string);
begin
  inherited Create;
  Name := aName;
end;

constructor Tsubscription.Create(const aName: string);
begin
  inherited Create(aName);
  fBilling := TMyObject.Create('bill');
end;

destructor Tsubscription.Destroy;
begin
  fBilling.Free;
end;

function Tsubscription.getfBillingObj(const aRttiProperty: TRttiProperty): TMyObject;
begin
  Result := aRttiProperty.GetValue(Self).AsType<TMyObject>;
end;

var
  Ctx: TRttiContext;
  prop: TRttiProperty;
  sub: Tsubscription;
  bill: TMyObject;
begin
  sub := Tsubscription.Create('sub');
  try
    prop := ctx.GetType(Tsubscription).GetProperty('billing');
    bill := sub.getfBillingObj(prop);
    // bill.Name is 'bill' as expected...
  finally
    sub.Free;
  end;
end;

也就是说,在这种情况下没有必要使用 RTTI,因为 TSubscription 可以直接访问它自己的内部字段:

function TSubscription.getfBillingObj: TMyObject 
begin
  Result := fBilling;
end; 

但即使这样也是多余的,因为 billing 属性 是 public。任何调用者都可以按原样使用 billing 属性:

var
  sub: Tsubscription;
  bill: TMyObject;
begin
  sub := Tsubscription.Create('sub');
  try
    bill := sub.billing;
    // bill.Name is 'bill' as expected...
  finally
    sub.Free;
  end;
end;