DELPHI:泛型和多态性 [英] DELPHI: Generics and polymorphism
问题描述
已经有几种不同的方法被问到了 - 但是我还没有找到答案。
This has been asked several different ways already - but I haven't found my answer yet.
有人可以为我解释一些事情。
使用:Delphi XE2
Can someone clarify a few things for me please. Using : Delphi XE2
我有相当大的BaseObject,我几乎用于所有的东西。
与此同时,我有一个通用列表 - BaseList。
I have quite a big BaseObject that I use for almost everything. Along with it I have a Generic list - BaseList.
付款如下:
TBaseObject = class
... a lot of properties and methods ...
end;
TBaseList<T: TBaseObject> = class(TObjectList<T>)
... some properties and methods ...
end;
我最近尝试使用Objects []属性从旧的TStringList更改TBaseList声明。对于这个从未更通用的泛型列表TObjectList。
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.
但是我遇到了一些问题。
BaseUnit是一个文件...每次我下载我的BaseObject我也会做一个专门的列表来跟踪它。
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.
所以我会去做类似于:
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;
由于BaseList和BaseObject是我的层次结构的顶层,我假设这样的列表将能够保存任何列表我可以想到。
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.
但我有一种感觉,在这里我失败了...
a TBaseList< TBaseobject>
在某种程度上不可比 TCustomerList< TCustomer>
...
即使 TCustomerList
和 TCustomer
是从我的基础。
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.
我希望能够在baselist中使用泛型镇压新对象
ie。在填充方法中使用 T.Create
。
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?
推荐答案
Delphi泛型不支持协方差和逆变,所以您尝试做的是不可能使用语言的当前语法。我建议您阅读以下有关更多细节的博客文章。
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.
- Craig Stuntz: Comparing C#, C++, and Delphi (Win32) Generics
- Mason Wheeler: Generics and the Covariance Problem
从根本上说,您尝试做的是这样的:
Fundamentally what you are attempting to do is this:
type
TBase = class;
TDerived = class(TBase);
TBaseList = TList<TBase>;
TDerivedList = TList<TDerived>;
var
BaseList: TBaseList;
DerivedList: TDerivedList;
...
BaseList := TDerivedList;//does not compile
设计师没有阻止你这样做。有一个很好的理由请考虑以下标准示例:
The designers have not stopped you doing this out of spite. There is a good reason. Consider the following standard example:
type
TAnimal = class;
TCat = class(TAnimal);
TPenguin = class(TAnimal);
var
AnimalList: TList<TAnimal>;
CatList: TList<TCat>;
Penguin: TPenguin;
...
AnimalList := CatList;//does not compile because...
AnimalList.Add(Penguin);//...of the danger of this
尽管将 TPenguin
添加到 TList< TAnimal>
, AnimalList
所指的实际列表是 TList< TCat& code>和企鹅不是一只猫。
Whilst it is reasonable to add a TPenguin
to a TList<TAnimal>
, the actual list that AnimalList
refers to is a TList<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.
aList := aCustomerList;//does not compile
aList.Add(aCustomPerson);
//this would add a TCustomPerson instance to a list containing
//TCustomer instances, but a TCustomPerson is not a TCustomer
这篇关于DELPHI:泛型和多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!