2015-08-20 22 views
2

在下面的代碼中我定義了兩個方法指針類型。我需要另一個接受任何這些類型參數的過程,並根據其他值使用它。但我不能找到這兩種類型的基類型,以便能夠既傳遞到程序:是否有方法指針的基類型?

type 
    TIntProc: procedure (I: Integer) of object; 
    TStrProc: procedure (S: string) of object; 

.... 

    procedure TForm1.CallbackTest(A: Integer; Callback: procedure of object {What type should I use here?}); 
    var 
    IntProc: TIntProc; 
    StrProc: TStrProc; 
    begin 
    if A = 1 then begin 
     IntProc:= TIntProc(Callback); 
     IntProc(100); 
    end else begin 
     StrProc:= TStrProc(Callback); 
     StrProc('Hello'); 
    end; 
    end; 

    procedure TForm1.MyIntProc(I: Integer); 
    begin 
    ShowMessage(IntToStr(I)); 
    end; 

    procedure TForm1.MyStrProc(S: string); 
    begin 
    ShowMessage(S); 
    end; 

我應該能夠編寫:

CallbackTest(1, MyIntProc); 

也:

CallbackTest(2, MyStrProc); 

但我肯定會得到錯誤,因爲procedure of object用作第二個參數的類型不是procedure (I: Integer) of objectprocedure (S: string) of object的基本類型。任何想法如何做到這一點?

回答

3

過程類型沒有繼承。您無法通過單一參數傳遞任何類型的類型安全方法。你需要施放。例如,您可以在程序類型變量和TMethod之間typecast

// Health warning, this code is for illustration, I do not endorse its use 

procedure Foo(A: Integer; Callback: TMethod); 
begin 
    if A = 1 then 
    TIntProc(Callback)(100) 
    else 
    TStrProc(Callback)('Hello'); 
end; 

.... 

Foo(1, TMethod(IntProc)); 
Foo(2, TMethod(StrProc)); 

但是,如果一個更好的可我不推薦這種做法。尤其是因爲您必須使用未經檢查的強制轉換,因此甚至不會從運行時檢查中受益,該運行時檢查可用於as運算符的類。

個人而言,我想這解決不同的方式:

public 
    procedure Foo(Callback: TIntProc); overload; 
    procedure Foo(Callback: TStrProc); overload; 

如果你需要一個程序來處理這兩個回調方法,做出額外的私人超載:

private 
    procedure Foo(IntCallback: TIntProc; StrCallback: TStrProc); overload; 

實現這樣的:

procedure TMyClass.Foo(IntCallback: TIntProc; StrCallback: TStrProc); 
begin 
    if Assigned(IntCallback) then 
    .... 
    if Assigned(StrCallback) then 
    .... 
end; 

然後執行像這樣的公開重載:

procedure TMyClass.Foo(Callback: TIntProc); 
begin 
    Foo(Callback, nil); 
end; 

procedure TMyClass.Foo(Callback: TStrProc); 
begin 
    Foo(nil, Callback); 
end; 
+0

您可以詳細說明對TMethod進行類型轉換嗎?我必須使用方法指針,並且重載解決方案不符合我的要求。 –

+0

重載方法適合這個問題。也許你真正的問題與問題不同。你說,「我必須使用方法指針」。精細。我答案中的代碼使用方法指針。爲什麼你不得不放棄類型安全?你明白這個的後果嗎? –

+0

至於類型轉換,我假設你知道類型轉換是什麼。我鏈接到類型轉換的文檔。你知道什麼是類型轉換嗎?我只是想弄清楚什麼樣的水平。 –

2

隨着一點點的幫助,通用這是可能的:

program Project14; 

{$APPTYPE CONSOLE} 

uses 
    System.SysUtils,TypInfo; 

Type 
    TMyProcedures = record 
    procedure MyIntProc(I: Integer); 
    procedure MyStrProc(S: String); 
    end; 

    TMyRec = record 
    public 
     class procedure CallbackTest<T>(Callback: TProc<T>); static; 
    end; 

class procedure TMyRec.CallbackTest<T>(Callback: TProc<T>); 
begin 
    case GetTypeKind(T) of 
    tkInteger: 
    begin 
     if GetTypeData(TypeInfo(T))^.OrdType = otSLong then 
     TProc<Integer>(Callback)(100); 
    end; 
    tkUString: 
    TProc<String>(Callback)('Hello'); 
    end; 
    else raise Exception.Create('Callback type can only be string or integer'); 
end; 

procedure TMyProcedures.MyIntProc(I: Integer); 
begin 
    WriteLn(IntToStr(I)); 
end; 

procedure TMyProcedures.MyStrProc(S: string); 
begin 
    WriteLn(S); 
end; 

var 
    myProcedures: TMyProcedures; 

begin 
    TMyRec.CallbackTest<Integer>(myProcedures.MyIntProc); 
    TMyRec.CallbackTest<String>(myProcedures.MyStrProc); 
    ReadLn; 
end. 

的一種方法是通過電話TypeInfo解決,類型轉換修復回調方法。

之前的版本中德爾福XE7你可以使用下面的代碼CallBackTest

class procedure TMyRec.CallbackTest<T>(Callback: TProc<T>); 
begin 
    if TypeInfo(T) = TypeInfo(Integer) then begin 
     if GetTypeData(TypeInfo(T))^.OrdType = otSLong then 
     TProc<Integer>(Callback)(100); 
    end 
    else if TypeInfo(T) = TypeInfo(String) then begin 
    TProc<String>(Callback)('Hello'); 
    end 
    else raise Exception.Create('Callback type can only be string or integer'); 
end; 

與類型安全的方式更新到實際的有序類型分開整數和代碼,會爲工作Delphi 2009..XE6。

+0

這不回答我的問題。我必須使用方法指針(即object的過程)。 –

+0

這適用於'程序的對象'和簡單的程序。只是試試看。 – linluk

+0

GetTypeKind讓編譯器做出選擇,而不是讓運行時開關 –

相關問題