delphi TOwnedCollection和使用多个继承的TCollectionItem

xu3bshqb  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(205)

我在同一个TOwnedCollection中添加自己的TCollectionItem类(继承自TCollectionItem)时遇到问题。
我参考了Indy的IdMessageParts.pas作为TIdMessagePart的推荐。所以我一定是错过了什么,因为我得到了一个“无效的类类型”错误时,添加TMyItem2
我希望MyItems: TOwnedCollection能够存储TMyItemTMyItem2TMyItem3。但是在添加TMyItem2TMyItem3时,我收到了“Invalid typecast”错误(仅可接受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
  function Add: TMyItem;
  function IndexOf(aFieldName: string): Integer;
  function MyItemByFieldName(aFieldName: string): TMyItem;
  property Items[aIndex: Integer]: TMyItem read GetMyItem; default;
end;

// NOTE: in idMessageParts.pas the add is defined this way
// which I don't quite understand
{
function TIdMessageParts.Add: TIdMessagePart;
begin
  // This helps prevent TIdMessagePart from being added
  Result := nil;
end;
}

// this is the calling code
with MyItems.Add do
begin
  LabelName := 'test';  // works
end;
// Error of invalid typecast occurred here
with MyItems.Add as TMyItem2 do  // typecast error here
begin
  LabelName := 'label item2';
  Caption := 'caption item2';
end;
with MyItems.Add as TMyItem3 do  // typecast error here
begin
  LabelName := 'label item2';
  Caption := 'caption item2';
  Caption3 := 'caption3 item2';
end;
hmtdttj4

hmtdttj41#

继承的TCollection.Add()方法创建了TCollection构造函数中指定的类类型的示例,所以Add()在处理多个TCollectionItem派生的类时是无用的,因为你不能用这种方法添加多个类。
此代码:

with MyItems.Add do
begin
 ...
end;

因为您告诉TMyItems它的项目类别类型是TMyItem,所以Add()会建立TMyItem
此代码:

with MyItems.Add as TMyItem2 do
...
with MyItems.Add as TMyItem3 do

失败的原因是相同的。你告诉TMyItems创建TMyItem对象,所以你不能把它们转换成你的其他类类型。
Indy的TIdMessageParts集合覆盖了Add(),以阻止用户以这种方式使用Add()
要完成您想要的(以及Indy所做的),您需要调用TCollectionItem构造函数,而不是使用Add(),例如:

with TMyItem.Create(MyItems) do
begin
  LabelName := 'test';  // works
end;

with TMyItem2.Create(MyItems) do
begin
  LabelName := 'label item2';
  Caption := 'caption item2';
end;

with TMyItem3.Create(MyItems) do
begin
  LabelName := 'label item2';
  Caption := 'caption item2';
  Caption3 := 'caption3 item2';
end;

相关问题