2016-11-01 25 views
0

我有一個TRttiProperty變量命名aRttiProperty,指向下面的屬性:RTTI:如何獲取字段的對象指針?

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

現在,我怎麼能提取aRttiPropertyfBilling對象的指針?

我嘗試做這樣的,但它不工作:

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

它返回父TSubscription對象,而不是fbilling場的對象。

+0

那麼這僅僅是矯枉過正,當你可以使用'結果:= MySubscriptionInstance.Billing;'代替。 –

+0

@Remy - 我的猜測是Loki想寫給這個領域。 –

+0

@SertacAkyuz:如果他需要'fBilling'字段本身的內存地址,那麼通過'TRttiProperty'並不是正確的方法(除非將其類型轉換爲「TRttiInstanceProperty」,然後解碼其PropInfo ^。 SetProc'值)。一個更好的選擇是通過使用'aRttiType.GetField('fBilling')Offset'(其中'aRttiType'代表'TSubscription'類)在'Tsubscription'類中獲得'fBilling'字段的偏移量,然後將該偏移量添加到「Tsubscription」對象的起始內存地址。 –

回答

4

您在問題中顯示的代碼非常好(只要您將Tsubscription類聲明修復爲包含getfBillingObj()方法即可)。該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屬性是公共區域C。任何調用者可以只使用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; 
+0

我沒有意識到試圖獲取指針的代碼是在它作爲其字段的類中。渲染RTTI相當冗餘.. –

+1

感謝雷米!完美的答案...我發現我的代碼中的錯誤感謝您確認aRttiProperty.GetValue(Self).AsType ;是好方法:)其實我在做Fbilling:= TMyObject(Self);而不是Fbilling:= TMyObject.create(Self); ....愚蠢的「視覺」錯誤:( – loki