DELPHI:泛型和多态性
已经有人以几种不同的方式问过这个问题 - 但我还没有找到答案。
有人可以帮我澄清一些事情吗? 使用:Delphi XE2
我有一个相当大的 BaseObject,我几乎用它来做所有事情。 除此之外,我还有一个通用列表 - BaseList。
声明如下:
TBaseObject = class
... a lot of properties and methods ...
end;
TBaseList<T: TBaseObject> = class(TObjectList<T>)
... some properties and methods ...
end;
我最近尝试将 TBaseList 声明从使用 Objects[] 属性的非常旧的 TStringList 更改为这个从未更通用的泛型列表 TObjectList。
但我遇到了一些问题。 BaseUnit 是一个文件……每次我下降 BaseObject 时,我也会制作一个专门的列表来跟踪它。
所以我会去做类似的事情:
TCustomer = class(TBaseObject)
... customer related stuff ...
end;
TCustomerList<T: TCustomer> = class(TBaseList<T>)
... customer list specific stuff ...
end;
但现在我想要一个对象包含一个列表 - 可以容纳任何对象。 我想我可以这样做,
TControlObject = class(TBaseobject)
FGenList: TBaseList<TBaseObject>;
end;
因为 BaseList 和 BaseObject 是我的层次结构的顶部,我认为这样的列表将能够保存我能想到的任何列表。
但我有一种感觉,我在这里失败了...... TBaseList
在某种程度上无法与 TCustomerList
相比较... 即使 TCustomerList
和 TCustomer
是我的基地的后裔。
我希望能够在基列表中使用泛型来实例化新对象。 IE。在填充方法中使用T.Create
。
这是完整层次结构的示例:
Base Unit;
TBaseObject = class
end;
TBaseList<T:TBaseObject> = class(TObjectList<T>)
end;
CustomCustomer Unit;
TCustomCustomer = class(TBaseObject)
end;
TCustomCustomerList<T:TCustomCustomer> = class(TBaseList<T>)
end;
Customer Unit;
TCustomer = class(TCustomCustomer)
end;
TCustomerList<T:TCustomer> = class(TCustomCustomerList<T>)
end;
CustomPerson Unit;
TCustomPerson = class(TBaseObject)
end;
TCustomPersonList<T:TCustomPerson> = class(TBaseList<T>)
end;
Person Unit;
TPerson = class(TCustomPerson)
end;
TPersonList<T:TPerson> = class(TCustomPersonList<T>)
end;
鉴于上面的层次结构 - 为什么我不能:
var
aList : TBaseList<TBaseObject>; // used as a list parameter for methods
aPersonList : TPersonList<TPerson>;
aCustomerList : TCustomerList<TCustomer>;
begin
aPersonList := TPersonList<TPerson>.Create;
aCustomerList := TCustomerList<TCustomer>.Create;
aList := aCustomerList; <-- this FAILS !! types not equal ..
end;
调用处理所有列表的基类的过程以同样的方式失败......
Procedure LogStuff(SomeList : TBaseList<TBaseObject>)
begin
writeln(Format( 'No. Elements in list : %d',[SomeList.Count]));
end;
有人可以打我并告诉我我在这里做错了什么吗?
This has been asked several different ways already - but I haven't found my answer yet.
Can someone clarify a few things for me please.
Using : Delphi XE2
I have quite a big BaseObject that I use for almost everything.
Along with it I have a Generic list - BaseList.
Delarations go like this :
TBaseObject = class
... a lot of properties and methods ...
end;
TBaseList<T: TBaseObject> = class(TObjectList<T>)
... some properties and methods ...
end;
I have recently tried to change the TBaseList declaration from a very old TStringList using Objects[] property... to this never more versatile Generics list TObjectList.
But I run into some problems.
The BaseUnit is one file ... and every time I descend my BaseObject I also make a specialized list to follow it.
So I would go and do something like :
TCustomer = class(TBaseObject)
... customer related stuff ...
end;
TCustomerList<T: TCustomer> = class(TBaseList<T>)
... customer list specific stuff ...
end;
But now I would like an object to contain a list - that can hold any object.
And I thought I could do it like this
TControlObject = class(TBaseobject)
FGenList: TBaseList<TBaseObject>;
end;
Since BaseList and BaseObject is top of my hierarchy I assumed that such a List would be able to hold any list I could think of.
But I have a feeling that it is here I fail ...
a TBaseList<TBaseobject>
is somehow not comparable to TCustomerList<TCustomer>
...
Even if TCustomerList
and TCustomer
is descended from my base.
I was hoping to be able to use generics in the baselist for instaciating new objects.
ie. using T.Create
in a populate method.
Here is example of complete hierarchy:
Base Unit;
TBaseObject = class
end;
TBaseList<T:TBaseObject> = class(TObjectList<T>)
end;
CustomCustomer Unit;
TCustomCustomer = class(TBaseObject)
end;
TCustomCustomerList<T:TCustomCustomer> = class(TBaseList<T>)
end;
Customer Unit;
TCustomer = class(TCustomCustomer)
end;
TCustomerList<T:TCustomer> = class(TCustomCustomerList<T>)
end;
CustomPerson Unit;
TCustomPerson = class(TBaseObject)
end;
TCustomPersonList<T:TCustomPerson> = class(TBaseList<T>)
end;
Person Unit;
TPerson = class(TCustomPerson)
end;
TPersonList<T:TPerson> = class(TCustomPersonList<T>)
end;
Given the above hierarchy - why can't I :
var
aList : TBaseList<TBaseObject>; // used as a list parameter for methods
aPersonList : TPersonList<TPerson>;
aCustomerList : TCustomerList<TCustomer>;
begin
aPersonList := TPersonList<TPerson>.Create;
aCustomerList := TCustomerList<TCustomer>.Create;
aList := aCustomerList; <-- this FAILS !! types not equal ..
end;
Calling a procedure that handles the base class for all lists fails the same way ...
Procedure LogStuff(SomeList : TBaseList<TBaseObject>)
begin
writeln(Format( 'No. Elements in list : %d',[SomeList.Count]));
end;
Can someone punch me and tell me what I'm doing wrong here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Delphi 泛型不支持协变和逆变,因此您尝试执行的操作在该语言的当前语法中是不可能的。我建议您阅读以下博客文章,其中更详细地介绍了该问题。
从根本上讲,您正在尝试做的是:
设计者并没有出于恶意而阻止您这样做。这是有充分理由的。考虑以下标准示例:
虽然将
TPenguin
添加到TList
是合理的,但AnimalList
引用的实际列表是TList
并且企鹅不是猫。而且,如果您想在示例层次结构的上下文中考虑它,这里有一个证明语言设计合理的代码说明。
Delphi generics do not support covariance and contravariance so what you are attempting to do is not possible with the language's current syntax. I suggest you have a read of the following blog articles that cover the matter in more detail.
Fundamentally what you are attempting to do is this:
The designers have not stopped you doing this out of spite. There is a good reason. Consider the following standard example:
Whilst it is reasonable to add a
TPenguin
to aTList<TAnimal>
, the actual list thatAnimalList
refers to is aTList<TCat>
and a penguin is not a cat.And, if you want to think of it in the context of your example hierarchy, here's an illustration of code that justifies the language design.