我想创建一个TObjectList<T>
后代来处理我的应用中对象列表之间的常见功能。然后我想进一步从新类继续下载,以便在需要时引入其他功能。我似乎无法使用超过1级的继承。我可能需要更多地了解泛型,但是我搜索高低都是正确的方法来做到这一点而没有成功。到目前为止,这是我的代码:
unit edGenerics;
interface
uses
Generics.Collections;
type
TObjectBase = class
public
procedure SomeBaseFunction;
end;
TObjectBaseList<T: TObjectBase> = class(TObjectList<T>)
public
procedure SomeOtherBaseFunction;
end;
TIndexedObject = class(TObjectBase)
protected
FIndex: Integer;
public
property Index: Integer read FIndex write FIndex;
end;
TIndexedObjectList<T: TIndexedObject> = class(TObjectBaseList<T>)
private
function GetNextAutoIndex: Integer;
public
function Add(AObject: T): Integer;
function ItemByIndex(AIndex: Integer): T;
procedure Insert(AIndex: Integer; AObject: T);
end;
TCatalogueItem = class(TIndexedObject)
private
FID: integer;
public
property ID: integer read FId write FId;
end;
TCatalogueItemList = class(TIndexedObjectList<TCatalogueItem>)
public
function GetRowById(AId: Integer): Integer;
end;
implementation
uses
Math;
{ TObjectBase }
procedure TObjectBase.SomeBaseFunction;
begin
end;
{ TObjectBaseList<T> }
procedure TObjectBaseList<T>.SomeOtherBaseFunction;
begin
end;
{ TIndexedObjectList }
function TIndexedObjectList<T>.Add(AObject: T): Integer;
begin
AObject.Index := GetNextAutoIndex;
Result := inherited Add(AObject);
end;
procedure TIndexedObjectList<T>.Insert(AIndex: Integer; AObject: T);
begin
AObject.Index := GetNextAutoIndex;
inherited Insert(AIndex, AObject);
end;
function TIndexedObjectList<T>.ItemByIndex(AIndex: Integer): T;
var
I: Integer;
begin
Result := Default(T);
while (Count > 0) and (I < Count) and (Result = Default(T)) do
if Items[I].Index = AIndex then
Result := Items[I]
else
Inc(I);
end;
function TIndexedObjectList<T>.GetNextAutoIndex: Integer;
var
I: Integer;
begin
Result := 0;
for I := 0 to Count - 1 do
Result := Max(Result, Items[I].Index);
Inc(Result);
end;
{ TCatalogueItemList }
function TCatalogueItemList.GetRowById(AId: Integer): Integer;
var
I: Integer;
begin
Result := -1;
for I := 0 to Pred(Self.Count) do
if Self.Items[I].Id = AId then
begin
Result := I;
Break;
end;
end;
end.
/////// ERROR HAPPENS HERE ////// ???? why is beyond me
看来,以下声明:
>>> TCatalogueItemList = class(TIndexedObjectList<TCatalogueItem>) <<<<
导致以下编译器错误:
[DCC错误] edGenerics.pas(106):E2010不兼容的类型: 'TCatalogueItem'和'TIndexedObject'
然而编译器在编译单元的END处显示错误(第106行),而不是声明本身,这对我没有任何意义......
基本上我的想法是我有一个从TObjectList开始的通用列表,我可以根据需要使用新功能进行扩展。任何有关这方面的帮助都会很棒!!!
我应该使用Delphi 2010添加。
感谢。
答案 0 :(得分:9)
您的错误是在类型转换中,并且编译器错误正常(但它无法在我的Delphi XE3中找到正确的文件)。
声明了ItemByIndex方法:
TIndexedObjectList<T>.ItemByIndex(AIndex: Integer): T;
但是你有这条线:
Result := TIndexedObject(nil);
这适用于父类TIndexedObjectList
,其中函数的结果类型为TIndexedObject
,,但对于后代类< / strong> TCatalogueItemList
,其中函数的结果是TCatalogueItem
类型。
您可能知道,TCatalogueItem
实例的赋值与TIndexedObject
变量兼容,但情况恰恰相反。它转化为这样的东西:
function TCatalogueItemList.ItemByIndex(AIndex: Integer): TCatalogueItem;
begin
Result := TIndexedObject(nil); //did you see the problem now?
要将结果初始化为nil值,可以调用Default()伪函数,如下所示:
Result := Default(T);
在Delphi XE或更高版本中,该解决方案也是通用的。不是将结果类型转换为固定的TIndexedObjectList
类,而是使用T类型应用泛型类型转换
Result := T(nil);
//or
Result := T(SomeOtherValue);
但是,在这种特定情况下,不需要输入nil
常量,因为nil
是一个与任何引用兼容的特殊值,所以你只需用以下代码替换:
Result := nil;
它将编译,并希望按预期工作。