2009-11-19 44 views
2

基於較早的post,我寫了下面的代碼。請原諒這篇文章的冗長。我相信各方都可以提供完整的代碼進行測試和評論。德爾福:泛型和「is」操作符問題

program sandbox; 
{$APPTYPE CONSOLE} 

uses 
    SysUtils, 
    Generics.Collections; 

type 
    TDataType = class 
    // Stuff common to TInt and TStr 
    end; 

    TInt = class(TDataType) 
    FValue: integer; 
    constructor Create(Value, Low, High: integer); 
    end; 

    TStr = class(TDataType) 
    FValue: string; 
    constructor Create(Value: string; Length: integer); 
    end; 

    TSomeClass = class 
    FIntList: TList<TInt>; 
    FStrList: TList<TStr>; 
    procedure AddToList<T: TDataType>(Element: T); 
    constructor Create(); 
    procedure Free(); 
    end; 

constructor TInt.Create(Value, Low, High: Integer); 
begin 
    inherited Create(); 
    FValue := Value; 
end; 

constructor TStr.Create(Value: string; Length: Integer); 
begin 
    inherited Create(); 
    FValue := Value; 
end; 

procedure TSomeClass.AddToList<T>(Element: T); 
begin 
    if TObject(Element) is TInt then 
    FIntList.Add(Element) 
    else if TObject(Element) is TStr then 
    FStrList.Add(Element); 
end; 

constructor TSomeClass.Create(); 
begin 
    inherited; 
    FIntList := TList<TInt>.Create(); 
    FStrList := TList<TStr>.Create(); 
end; 

procedure TSomeClass.Free(); 
var 
    SomeIntItem: TInt; 
    SomeStrItem: TStr; 
begin 
    for SomeIntItem in FIntList do begin 
    SomeIntItem.Free(); 
    end; 

    for SomeStrItem in FStrList do begin 
    SomeStrItem.Free; 
    end; 

    FIntList.Free(); 
    FStrList.Free(); 
end; 

var 
    Inst: TSomeClass; 

begin 
    try 
    { TODO -oUser -cConsole Main : Insert code here } 

    Inst := TSomeClass.Create; 
    Inst.AddToList(TInt.Create(100, 0, 101)); 
    Inst.AddToList(TStr.Create('Test', 10)); 
    Inst.Free; 

    except 
    on E:Exception do 
    Writeln(E.Classname, ': ', E.Message); 
    end; 
end. 

注意的TIntTStr在現實世界中的構造函數可以利用Low, High: integerLength: integer參數以及。我在運行Delphi 2009的if TObject(Element) is TInt thenelse if TObject(Element) is TStr then上有一個「E2089無效的類型轉換」。有誰知道爲什麼會發生這種情況?

編輯:請注意,TIntTStr只是兩個可能10-20其他類型;否則超載是該工作的工具。 :)

+0

你的聲明和實現AddToList的不同。我對泛型沒有足夠的瞭解,但對於普通的帕斯卡來說,這是錯誤的。 – 2009-11-19 07:48:14

+0

嗨列文!我認爲你指的是與簽名「procedure AddToList (Element:T)」相比,實現「procedure TSomeClass.AddToList (Element:T)」?如果是這樣,對你的評論的迴應是RAD工作室不希望對實際實施產生限制。 – conciliator 2009-11-19 08:26:07

+0

啊,我明白了。對於那些尚未納入仿製藥領域的人來說,至少最明顯的是現在已經不存在了。感謝您清理它。 – 2009-11-19 08:28:52

回答

7

重新考慮你的設計。你可以只使用過載,而不是一個泛型類型參數的,比如:

procedure Add (SomeString : TString); overload; 
procedure Add (SomeInt : TInt); overload; 

或者,如果你想使用多態做什麼Gamecat建議,只是傳遞的基本類型作爲參數,對參數使用is

procedure Add (Element : TDataType);   

就像Rob在你對上一個問題的評論中指出的那樣:如果你只允許兩種類型並且有基於實際類型的條件,那麼它就不是通用的。所以泛型可能是這裏的錯誤工具。

希望有所幫助。

+0

它沒有編譯器錯誤。它缺少一個類型轉換;-)。但我同意錯誤的工具評論。 – 2009-11-19 08:18:55

+0

我誤解了這個問題。我已經更新了我的答案。 – jpfollenius 2009-11-19 08:25:37

+0

謝謝粉碎者!我意識到,我應該從一開始就指出,TInt和TStr將同時還有其他10多種類型。我不知道TypeInfo()方法,所以+1! :) – conciliator 2009-11-19 08:42:51

3

問題不在於泛型。您將TDataType添加到期望TInt或TStr的列表中:

procedure TSomeClass.AddToList<T>(Element: T); 
begin 
    if TObject(Element) is TInt then 
    FIntList.Add(TInt(Element)) 
    else if TObject(Element) is TStr then 
    FStrList.Add(TStr(Element)); 
end; 

解決問題。

但是,爲什麼不使用:

procedure TSomeClass.AddToList(Element: TDataType); 
begin 
    if Element is TInt then 
    FIntList.Add(TInt(Element)) 
    else if Element is TStr then 
    FStrList.Add(TStr(Element)); 
end; 
+0

+1你顯然比我更好地閱讀了這個問題。 – jpfollenius 2009-11-19 08:21:51

+0

謝謝,Gamecat!最後一個例子編譯得很好。然而,我仍然使用你的第一個例子(嘗試T:TDataType,T:class和空約束)得到一個類型轉換錯誤。你有沒有得到它編譯? – conciliator 2009-11-19 08:40:09

+0

@Gamecat:或許我一開始並不清楚?它是在「如果TObject(元素)是TInt然後」和「否則如果TObject(元素)是TStr然後」的語句中的類型轉換「那麼你知道爲什麼嗎? – conciliator 2009-11-19 09:46:29