首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Delphi中的持久化多态列表

Delphi中的持久化多态列表
EN

Stack Overflow用户
提问于 2015-08-22 04:12:44
回答 3查看 647关注 0票数 2

我需要一个多态对象列表(不同的对象类,但有一个共同的基类),我可以‘持久化’作为表单文件的一部分。

TList不是持久性的,TCollection也不是多态的。

我可能会自己滚,但我不喜欢重复发明轮子。想法?

EN

回答 3

Stack Overflow用户

发布于 2015-08-22 04:48:59

没有一个标准库类能满足您的需求。您需要使用自己的库,或者找到第三方库。

票数 3
EN

Stack Overflow用户

发布于 2015-08-22 20:23:49

为了使用默认的流框架,你必须创建包装器集合项,它可以保存和创建不同类的对象实例。

代码语言:javascript
复制
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编辑器,但这是开始的基础。

代码语言:javascript
复制
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 (作为表单的一部分)的外观:

代码语言:javascript
复制
  object TestComponent1: TTestComponent
    List = <
      item
        ObjClassName = 'TFoo'
        Obj.Foo = 'abc'
      end
      item
        ObjClassName = 'TBar'
        Obj.Bar = 5
      end>
    Left = 288
    Top = 16
  end
票数 3
EN

Stack Overflow用户

发布于 2015-08-22 05:04:54

我不确定为什么TCollection不能容纳TCats和TDogs?

代码语言:javascript
复制
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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32148572

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档