已经有人以多种不同的方式问过这个问题 - 但我还没有找到答案。
有人可以帮我澄清一些事情吗? 使用:德尔福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<TBaseobject>
不知何故无法与 TCustomerList<TCustomer>
相比较...
即使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;
有人可以打我一下并告诉我我在这里做错了什么吗?
最佳答案
Delphi 泛型不支持协变和逆变,因此您尝试执行的操作在该语言的当前语法中是不可能的。我建议您阅读以下博客文章,其中更详细地介绍了该问题。
- 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
虽然添加 TPenguin
是合理的到 TList<TAnimal>
,实际列表为 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
关于DELPHI:泛型和多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9140485/