2014-03-27 52 views
5

我有一個線程庫有三個不同的方法類型的構造函數。我希望它們被合併爲一種邏輯,並在構造函數中將它們區分開來。可能嗎?由於值爲TValue,那麼對於方法類型是否有類似的情況?如何將任意類型的方法傳遞給過程並識別它?

我現在支持以下幾種類型;

TAgThreadMethod1 = procedure of object; 
TAgThreadMethod2 = procedure; 
TAgThreadMethod3 = procedure(const AThread: TAgThread) of object; 

和構造函數,像這樣:

constructor Create(const AOnRun: TAgThreadMethod1); overload; virtual; 
constructor Create(const AOnRun: TAgThreadMethod2); overload; virtual; 
constructor Create(const AOnRun: TAgThreadMethod3); overload; virtual; 

僅供參考,我不希望用戶有在施工後都改變的輔助方法在以後的時間的能力。所以如果有一個解決方案可以在一個構造函數中做這樣的事情,也是值得歡迎的;

constructor Create 
      (const AOnRun: [Some type which can hold arbitrary method types]); 
begin 

    // code to identify the method contained in AOnRun. 
    // if supported, assign it the correct handler. 

end; 

回答

5

沒有做到這一點沒有什麼好的辦法,因爲一個方法指針的整點在以後的某個點被調用,你不能這樣做,除非你知道它的簽名。因此,丟失簽名之間的區別非常適得其反。

如果您只想在對象中存儲一種類型的調用,那麼可以讓這三個構造函數創建一個匿名方法,並使用一個統一的簽名來封裝對這三種類型的調用,並將其存儲起來而不是處理多種不同的方法類型。但是,你所要求的,具體來說,將不起作用。

+0

好吧,我想我明白你的意思了。雖然,有沒有辦法通過rtti來識別方法指針的類型呢?我試圖容納多種類型的方法,所以我不必爲這些方法創建多個構造函數。 –

+1

@Umair:不,沒有辦法通過RTTI來識別方法指針。在內部,它只是一個指針。因爲每個對象都有一個引用其VMT的隱藏字段,並且VMT有一個指向RTTI表的指針,但是方法指針沒有類似的東西讓你在運行時做出這個決定。 –

+0

@Umair:另外,我不確切知道你在做什麼,但是當你說「線程庫需要多種方法指針類型」時,我想到的第一件事就是「我已經在[OmniThreadLibrary](http://otl.17slon.com/)中看到了一些非常相似的東西。「你看過嗎? –

4

我認爲你可以做的最好的是有一個構造函數,它接受過程類型的最一般形式。那是TProc<TAgThread>。這將是主構造函數,唯一的虛擬構造函數。然後,您可以將其他構造函數委託給主構造函數。

總括來說,在declaration in SysUtils是:

type 
    TProc<T> = reference to procedure(Arg1: T); 

所以,你的主構造函數是:

constructor Create(AOnRun: TProc<TAgThread>); overload; virtual; 

其他的構造函數不是虛擬的,可能是這樣的:

constructor Create(AOnRun: TAgThreadMethod1); overload; 

實施爲:

constructor TMyClass.Create(AOnRun: TAgThreadMethod1); 
begin 
    Create(
    procedure(Thread: TAgThread) 
    begin 
     AOnRun(); 
    end; 
); 
end; 

主構造函數,虛擬構造函數完成所有工作。其他的構造函數,非虛擬構造函數調整它們的參數以適應主構造函數的參數。

+2

'TProc '上的參數是** not ** const。 –

+1

@Stefan我一定在想我自己的版本,這是常量。人們不禁要問,emba人的思想是什麼。 –

1

這是可能的,但不是隻有一個TValue。

不是傳遞方法本身的,你可以把它作爲像這樣的TRttiMethod:MyRegisterMethod(TRttiContext.GetType(TMyClassType).GetMethod('MyMethodName')); 如果你想傳遞的所有構造函數,你將需要使用像這樣的循環:

for MyMethod in TRttiContext.GetType(TMyClassType).GetMethods do 
    if MyMethod.IsConstructor then // As in your example you only want constructors 
    MyRegisterMethod(MyMethod); 

後來,你可以這樣調用這個方法:MyRegisteredMethod.Invoke(nil, MyMethodParams)。 MyMethodParams是一個你需要提供的TValue數組。這可以存儲在TValue本身中(儘管將它們存儲在TArray中可能更容易)。請注意,在類方法的情況下,您只需要在調用中使用nil

如果要確保參數正常,可以通過在MyRttiMethod.GetParameters中查找並將其實際類型與TValue數組中的實際TValue類型進行比較來驗證它們。這也可以用來找到正確的方法。

+0

您的解決方案確實解決了在類中關聯的方法時遇到的問題,而不是那些沒有的方法。感謝您的洞察力。 –

+0

@Umair的確如此。在將方法聲明爲類型時,使用Rtti可能仍然可用。我目前無法嘗試,但它確實吸引我。也許本週晚些時候我會花點時間研究它。 – deColaman

相關問題