2015-08-21 55 views
2

我需要一個多態對象(不同的對象類,但具有一個公共基類)的列表,我可以'持久'作爲表單文件的一部分。德爾福中的持久性多態性列表

TList不是持久的,並且TCollection不是多態的。

我可以推出自己的產品,但不想重新發明輪子。想法?

+0

在何種意義上是'TCollection'不是多態? –

+0

@DavidHeffernan:'Add'和'insert'方法總是創建相同類型的TCollectionItem,當然? – Roddy

+0

@DavidHeffernan,我說他們總是創建您在構造函數中傳遞給TCollection的類類型。你不能擁有一個包含TDog和TCats的TAnimals TCollection。 (警告:錯誤的OO示例!)http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/Classes_TCollection_Create.html – Roddy

回答

3

沒有任何標準庫類可以滿足您的需求。你需要推出自己的,或找到第三方庫。

+0

我認爲這是你問的問題的答案。如果你想要圖書館的建議,這是關閉的話題,因爲我確信像你這樣的高級代表用戶都知道。 –

+0

謝謝。我試圖避免在購物清單問題的陰暗水域中出現這種結局。我當然不會特別要求圖書館,但如果這是答案...... – Roddy

+0

我認爲是。據我所知,標準庫中沒有任何可以開箱即可保存異構集合的集合。 –

0

我不確定TCollection爲什麼不能擁有TCats和TDogs?

TAnimal = class(TCollectionItem) 
end; 

TCat = class(TAnimal) 
end; 

TDog = class(TAnimal) 
end; 

FCollection : TCollection; 
FCollection := TCollection.Create(TAnimal); 

cat : TCat 
cat := TCat.Create(FCollection); 

dog : TDog 
dog := TDag.Create(FCollection); 

var 
    i : integer; 
begin 
    for I := 0 to FCollection.Count - 1 do 
    TAnimal(FCollection.Items[i]).DoSomething; 
end; 

FCollection現在將舉辦2項,一隻貓和一隻狗

或者我在這裏錯過了點?

+0

這就是我需要的,但它的工作?通常你使用'FCollection.Add'添加項目。 – Roddy

+0

是的,你是。考慮流式傳輸框架。 DFM文件。 –

+0

經過測試,它的工作原理 – GuidoG

3

對於使用默認流式框架,您必須創建包裝器集合項目,該項目可以保存並創建不同類別的對象實例。

unit PolyU; 

interface 

uses 
    System.SysUtils, 
    System.Classes; 

type 
    TWrapperItem = class(TCollectionItem) 
    protected 
    FObjClassName: string; 
    FObjClass: TPersistentClass; 
    FObj: TPersistent; 
    procedure SetObjClass(Value: TPersistentClass); 
    procedure SetObjClassName(Value: string); 
    procedure SetObj(Value: TPersistent); 
    function CreateObject(OClass: TPersistentClass): Boolean; dynamic; 
    public 
    property ObjClass: TPersistentClass read FObjClass write SetObjClass; 
    published 
    // ObjClassName must be published before Obj to trigger CreateObject 
    property ObjClassName: string read FObjClassName write SetObjClassName; 
    property Obj: TPersistent read FObj write SetObj; 
    end; 

implementation 

procedure TWrapperItem.SetObjClass(Value: TPersistentClass); 
begin 
    if Value <> FObjClass then 
    begin 
     FObj := nil; 
     FObjClass := Value; 
     if Value = nil then FObjClassName := '' 
     else FObjClassName := Value.ClassName; 
     CreateObject(FObjClass); 
    end; 
end; 

procedure TWrapperItem.SetObjClassName(Value: string); 
begin 
    if Value <> FObjClassName then 
    begin 
     FObj := nil; 
     FObjClassName := Value; 
     if Value = '' then FObjClass := nil 
     else FObjClass := FindClass(Value); 
     CreateObject(FObjClass); 
    end; 
end; 

procedure TWrapperItem.SetObj(Value: TPersistent); 
begin 
    FObj := Value; 
    if Assigned(Value) then 
    begin 
     FObjClassName := Value.ClassName; 
     FObjClass := TPersistentClass(Value.ClassType); 
    end 
    else 
    begin 
     FObjClassName := ''; 
     FObjClass := nil; 
    end; 
end; 

function TWrapperItem.CreateObject(OClass: TPersistentClass): Boolean; 
begin 
    Result := false; 
    if OClass = nil then exit; 
    try 
    FreeAndNil(FObj); 
    if OClass.InheritsFrom(TCollectionItem) then FObj := TCollectionItem(TCollectionItemClass(OClass).Create(nil)) 
    else 
    if OClass.InheritsFrom(TComponent) then FObj := TComponentClass(OClass).Create(nil) 
    else 
    if OClass.InheritsFrom(TPersistent) then FObj := TPersistentClass(OClass).Create; 
    Result := true; 
    except 
    end; 
end; 

end. 

類是打算由TWrapperItem包裹必須通過RegisterClassRegisterClasses方法用Delphi流媒體系統註冊。

以下測試組件包含可通過IDE進行編輯和流式傳輸的基本集合。對於更多的控制,你可能想編寫自定義的IDE編輯器,但這是從頭開始的基礎。

unit Unit1; 

interface 

uses 
    System.Classes, 
    PolyU; 

type 
    TFoo = class(TPersistent) 
    protected 
    FFoo: string; 
    published 
    property Foo: string read FFoo write FFoo; 
    end; 

    TBar = class(TPersistent) 
    protected 
    FBar: integer; 
    published 
    property Bar: integer read FBar write FBar; 
    end; 

    TTestComponent = class(TComponent) 
    protected 
    FList: TOwnedCollection; 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    published 
    property List: TOwnedCollection read FList write FList; 
    end; 

procedure Register; 

implementation 

procedure Register; 
begin 
    RegisterComponents('Test', [TTestComponent]); 
end; 

constructor TTestComponent.Create(AOwner: TComponent); 
begin 
    inherited; 
    FList := TOwnedCollection.Create(Self, TWrapperItem); 
end; 

destructor TTestComponent.Destroy; 
begin 
    Flist.Free; 
    inherited; 
end; 

initialization 

    RegisterClasses([TFoo, TBar]); 

finalization 

    UnRegisterClasses([TFoo, TBar]); 

end. 

這是怎麼流傳輸TTestComponent(如表的一部分)可以看起來像:

object TestComponent1: TTestComponent 
    List = < 
     item 
     ObjClassName = 'TFoo' 
     Obj.Foo = 'abc' 
     end 
     item 
     ObjClassName = 'TBar' 
     Obj.Bar = 5 
     end> 
    Left = 288 
    Top = 16 
    end 
+0

雖然您可能會試圖在TWrapperItem中使用泛型,但它不起作用,因爲[Delphi流式處理系統無法識別泛型類型的已發佈屬性](http://qc.embarcadero.com/wc/qcmain.aspx?d= 103296) –