有人可以为我解释一些事情吗
使用:Delphi XE2
我有一个相当大的BaSEObject,我几乎用于所有的东西.
随着它我有一个通用列表 – BaseList.
声明如下:
TBaSEObject = class ... a lot of properties and methods ... end; TBaseList<T: TBaSEObject> = class(TObjectList<T>) ... some properties and methods ... end;
我最近尝试从一个非常旧的TStringList使用Objects []属性…更改TBaseList声明到这个从未更通用的泛型列表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是我的层次结构的顶层,所以我认为这样一个List可以容纳任何可以想到的列表.
但我有一种感觉,在这里我失败了…
TBaseList< TBaSEObject>在某种程度上与TCustomerList< TCustomer>不相似…
即使TCustomerList和TCustomer都是从我的基础下降的.
我希望能够在baselist中使用仿制药来镇压新物体.
即.在填充方法中使用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;
有人可以打我,告诉我我在这里做错了吗?
解决方法
> Craig Stuntz: Comparing C#,C++,and Delphi (Win32) Generics
> Mason Wheeler: Generics and the Covariance Problem
从根本上说,你试图做的是这样的:
type TBase = class; TDerived = class(TBase); TBaseList = TList<TBase>; TDerivedList = TList<TDerived>; var BaseList: TBaseList; DerivedList: TDerivedList; ... BaseList := TDerivedList;//does not compile
设计师没有阻止你这样做.有一个很好的理由考虑以下标准示例:
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
尽管向TList< TAnimal>添加TPenguin是合理的,但是AnimalList引用的实际列表是TList< TCat>企鹅不是一只猫.
而且,如果你想在你的示例层次结构的上下文中考虑它,这里是一个证明语言设计的代码的例证.
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