TOwnedCollection 和使用多个继承的 TCollectionItem
TOwnedCollection and using multiple inherited TCollectionItem
我在同一 TOwnedCollection
.
中添加自己的 TCollectionItem
classes(继承自 TCollectionItem
)时遇到问题
我参考了 Indy 的 IdMessageParts.pas
作为推荐的 TIdMessagePart
。所以我一定是遗漏了一些东西,因为在添加 TMyItem2
.
时出现“无效的 class 类型”错误
我希望 MyItems: TOwnedCollection
能够存储 TMyItem
、TMyItem2
、TMyItem3
。但是在添加 TMyItem2
和 TMyItem3
时出现“无效类型转换”错误(只能接受 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;
继承的 TCollection.Add()
方法创建 TCollection
构造函数中指定的 class 类型的实例。所以 Add()
在处理多个 TCollectionItem
派生的 class 时没用,因为你不能那样添加多个 class。
此代码:
with MyItems.Add do
begin
...
end;
有效是因为您告诉 TMyItems
它的项目 class 类型是 TMyItem
,因此这就是 Add()
创建的内容。
此代码:
with MyItems.Add as TMyItem2 do
...
with MyItems.Add as TMyItem3 do
同样的原因失败了。您告诉 TMyItems
创建 TMyItem
对象,因此您不能将它们转换为其他 class 类型。
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;
我在同一 TOwnedCollection
.
TCollectionItem
classes(继承自 TCollectionItem
)时遇到问题
我参考了 Indy 的 IdMessageParts.pas
作为推荐的 TIdMessagePart
。所以我一定是遗漏了一些东西,因为在添加 TMyItem2
.
我希望 MyItems: TOwnedCollection
能够存储 TMyItem
、TMyItem2
、TMyItem3
。但是在添加 TMyItem2
和 TMyItem3
时出现“无效类型转换”错误(只能接受 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;
继承的 TCollection.Add()
方法创建 TCollection
构造函数中指定的 class 类型的实例。所以 Add()
在处理多个 TCollectionItem
派生的 class 时没用,因为你不能那样添加多个 class。
此代码:
with MyItems.Add do
begin
...
end;
有效是因为您告诉 TMyItems
它的项目 class 类型是 TMyItem
,因此这就是 Add()
创建的内容。
此代码:
with MyItems.Add as TMyItem2 do
...
with MyItems.Add as TMyItem3 do
同样的原因失败了。您告诉 TMyItems
创建 TMyItem
对象,因此您不能将它们转换为其他 class 类型。
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;