2013-06-21 71 views
6

可以說我有一個樣本類幫手德爾福類助手RTTI GetMethod

TSampleClassHelper = class helper for TSampleClass 
public 
    procedure SomeHelper; 
end; 

我做了以下內容:

var 
    obj :TSampleClass; 
begin 
    obj:=TSampleClass.Create; 
    obj.SomeHelper; 
end; 

,這按預期工作。

但我該如何使用RTTI來調用幫助器方法呢?以下似乎不起作用,GetMethod返回零。

var 
    obj :TSampleClass; 
    ctx :TRTTIContext; 
    rtype :TRTTIType; 
    rmethod :TRTTIMethod; 
begin 
    obj:=TSampleClass.Create; 
    rtype:=ctx.GetType(obj.ClassType); 
    rmethod:=rtype.GetMethod('SomeHelper'); // rmethod is nil ! 
end; 

那麼RTTI不適用於類助手中定義的方法嗎?有沒有辦法解決?

謝謝。

+0

我明白了,但在我的現實生活中的代碼我測試了「的someMethod」對任意對象。我不知道對象是否有通過助手定義的方法。所以我想這對通過類助手定義的'SomeMethod'不起作用。好吧。 –

回答

8

您的代碼返回nil方法的原因是該對象的類型不包含名爲SomeHelper的方法。包含該方法的類型是幫助器類型。

所以,你可以寫這樣它會返回一個非空方法:

obj:=TSampleClass.Create; 
rtype:=ctx.GetType(TypeInfo(TSampleClassHelper)); 
rmethod:=rtype.GetMethod('SomeHelper'); 

當然,你應該立即看到的第一個問題,即利用特定的編譯時類型,TSampleClassHelper。我們可以使用RTTI根據實例的類型在運行時發現TSampleClassHelper?不,我們不能,我會在下面解釋。

即使我們把它放在一邊,就我所見,無法使用RTTI調用該方法。如果您致電rmethod.Invoke(obj, []),則TRttiInstanceMethodEx.DispatchInvoke中的代碼會阻止嘗試調用輔助方法。它阻止它,因爲它聲明實例的類型與方法的類不兼容。相關的代碼是:

if (cls <> nil) and not cls.InheritsFrom(TRttiInstanceType(Parent).MetaclassType) then 
    raise EInvalidCast.CreateRes(@SInvalidCast); 

那麼,你可以獲得與rmethod.CodeAddress輔助方法的代碼地址,但你需要找到一些其他的方式來調用該方法。將它轉換爲具有適當簽名的方法並調用它很容易。但是爲什麼在任何情況下都打擾rmethod.CodeAddress?爲什麼不使用TSomeHelperClass.SomeMethod並將RTTI從循環中刪除?

討論

助手分辨率是基於在編譯點主動幫助靜態執行。一旦您嘗試使用RTTI調用輔助方法,則不存在幫助程序。你已經完成了編譯。所以你必須決定使用哪個助手類。在這一點上,你不需要RTTI。

這裏的根本問題是類助手方法解決方案基本上是一個使用編譯器上下文執行的靜態過程。由於在運行時沒有編譯器上下文,因此無法使用RTTI執行類助手方法解析。

爲了更深入地瞭解這個有艾倫·鮑爾的回答這裏的讀:Find all Class Helpers in Delphi at runtime using RTTI?

+0

這不是說有一個班級有多個助手。它是一些類有幫助者定義的必要方法,有些不。例如對於TStrings,我通過助手添加了方法,但對於TMyClass,它直接在類上定義。 –

+0

@AJ。真正的問題是編譯器基於編譯上下文靜態執行幫助器方法解析。這個概念與RTTI完全正交。 –