You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi中TCollectionItem能否将TFmxObject作为属性实现流序列化?

解决TFmxObject作为TCollectionItem属性无法序列化的问题

问题原因

TFmxObject继承自TPersistent,但FireMonkey的默认流处理机制不会自动序列化嵌套在**非TComponent类型的TPersistent(如TCollectionItem)**中的TFmxObject对象;再加上你的代码中FMyObject的Owner设为nil,流系统无法识别它属于TMyItem的子对象,因此跳过了其属性的序列化。

解决方案

以下是无需改变TMyObject继承自TFmxObject的前提下,实现序列化的可行方案:

方案1:利用[Aggregated]标记+手动定义序列化逻辑

通过给属性添加[Aggregated]标记告知流系统这是聚合对象,并重写DefineProperties方法明确序列化规则,同时正确设置子组件标记。

修改后的代码示例:

TMyItem = class(TCollectionItem)
private
  FName: string;
  FMyObject: TMyObject;
  procedure SetMyObject(const Value: TMyObject);
protected
  procedure DefineProperties(Filer: TFiler); override;
public
  constructor Create(Collection: TCollection); overload; override;
  destructor Destroy; override;
published
  property Name: string read FName write FName;
  // 添加[Aggregated]标记,标记为聚合对象
  property MyObject: TMyObject read FMyObject write SetMyObject [Aggregated];
end;

// TMyItems类代码为标准实现,此处省略

TMyObject = class(TFmxObject)
private var
  FObjectName: string;
published
  property ObjectName : string read FObjectName write FObjectName;
end;

///////////////////////////////////////////////////////
implementation

constructor TMyItem.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FMyObject := TMyObject.Create(nil);
  // 标记为子组件,让流系统递归序列化其属性
  FMyObject.SetSubComponent(True);
end;

destructor TMyItem.Destroy;
begin
  FMyObject.Free;
  inherited Destroy;
end;

procedure TMyItem.SetMyObject(const Value: TMyObject);
begin
  if FMyObject <> Value then
  begin
    FMyObject.Free;
    FMyObject := Value;
    if Assigned(FMyObject) then
    begin
      FMyObject.SetSubComponent(True);
      // 若集合的Owner是TComponent,可将其设为MyObject的Owner,否则保持nil
      if Assigned(Collection.Owner) then
        FMyObject.Owner := Collection.Owner;
    end;
  end;
end;

procedure TMyItem.DefineProperties(Filer: TFiler);
begin
  inherited;
  // 手动定义MyObject的序列化逻辑,确保流系统处理该对象
  Filer.DefineObjectProperty('MyObject', TMyObject,
    procedure var Value: TMyObject
    begin
      Value := FMyObject;
    end,
    procedure const Value: TMyObject
    begin
      SetMyObject(Value);
    end,
    Assigned(FMyObject));
end;

关键说明

  1. [Aggregated]标记:告诉流系统该属性是当前对象的一部分,需要随TMyItem一起序列化/反序列化。
  2. SetSubComponent(True):将TMyObject标记为子组件,触发流系统递归序列化其published属性(如ObjectName)。
  3. 重写DefineProperties:明确指定MyObject的序列化规则,避免流系统忽略该属性。

预期序列化结果

修改后,序列化内容会包含MyObject的属性:

MyItems = <
  item
    Name = 'Test1'
    MyObject = <
      ObjectName = 'Object1'
    >
  end
  item
    Name = 'Test2'
  end>

关于TMyObject.Create(self)无法工作的说明

TFmxObject的构造函数参数要求是TComponent类型的Owner,但TCollectionItem继承自TPersistent而非TComponent,因此不能直接传self。你可以将集合的Owner(如果集合属于某个TComponent)设为MyObject的Owner,或者保持Owner为nil,通过SetSubComponent和[Aggregated]标记让流系统识别即可。

内容的提问来源于stack exchange,提问作者Peter Jones

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 14:51:04