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;
关键说明
[Aggregated]标记:告诉流系统该属性是当前对象的一部分,需要随TMyItem一起序列化/反序列化。SetSubComponent(True):将TMyObject标记为子组件,触发流系统递归序列化其published属性(如ObjectName)。- 重写
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
相关产品推荐
相关产品推荐

