TOwnedCollection添加多类TCollectionItem子类报类型错误问题
问题根因
你的代码触发类型转换错误的核心原因有两点:
- 自定义的
TMyItems.Add方法默认只会创建基类TMyItem的实例,没有任何创建TMyItem2、TMyItem3子类实例的逻辑,对实际类型为基类的对象做as TMyItem2类型转换,必然抛出无效类型转换错误。 - 你没有理解Indy组件中
TIdMessageParts.Add返回nil的设计意图:这个写法是故意禁用无参数Add方法创建基类实例的能力,强制开发者显式指定要创建的集合项类型,避免生成不符合预期的基类对象。
修正方案
第一步:补充类引用声明,修改集合类Add方法
首先在TMyItem类定义前新增集合项的类引用类型,用于在Add方法中传入要创建的项类型,同时给集合类重载支持传入项类的Add方法:
// 声明集合项类引用,用于指定要创建的子类类型 TMyItemClass = class of TMyItem; TMyItem = class(TCollectionItem) private FLabelName: string; public constructor Create(Collection: TCollection); override; destructor Destroy; override; published property LabelName: string read FLabelName write FLabelName; end; TMyItem2 = class(TMyItem) private FCaption: string; published property Caption: string read FCaption write FCaption; end; TMyItem3 = class(TMyItem) private FCaption3: string; published property Caption3: string read FCaption3 write FCaption3; end; TMyItems = class(TOwnedCollection) private function GetMyItem(aIndex: Integer): TMyItem; protected constructor Create(aOwner: TAsapListview); function GetOwner: TPersistent; override; public // 无参Add和Indy逻辑一致,返回nil禁止直接创建基类 function Add: TMyItem; reintroduce; // 重载Add,传入项类创建对应类型的实例 function Add(ItemClass: TMyItemClass): TMyItem; reintroduce; function IndexOf(aFieldName: string): Integer; function MyItemByFieldName(aFieldName: string): TMyItem; property Items[aIndex: Integer]: TMyItem read GetMyItem; default; end;
第二步:实现Add方法的逻辑
function TMyItems.Add: TMyItem; begin Result := nil; end; function TMyItems.Add(ItemClass: TMyItemClass): TMyItem; begin // 传入什么类就创建什么类的实例,自动归属到当前集合 Result := ItemClass.Create(Self); end;
第三步:修改调用代码
创建集合项时显式传入要创建的项类型,不需要再用as做类型强转:
// 创建基类TMyItem实例 with MyItems.Add(TMyItem) do begin LabelName := 'test'; end; // 创建TMyItem2实例 with TMyItem2(MyItems.Add(TMyItem2)) do begin LabelName := 'label item2'; Caption := 'caption item2'; end; // 创建TMyItem3实例 with TMyItem3(MyItems.Add(TMyItem3)) do begin LabelName := 'label item3'; Caption3 := 'caption3 item3'; end;
说明:
TOwnedCollection原生支持存储继承自集合项基类的所有子类实例,不需要额外做类型注册。你之前的错误和集合的多态支持能力无关,纯粹是创建的对象实际类型和你要转换的目标类型不匹配导致的。
内容的提问来源于stack exchange,提问作者Peter Jones
相关产品推荐
相关产品推荐

