Delphi 泛型 TObjectList< T > 继承

Delphi generics TObjectList<T> inheritance

我想创建一个 TObjectList<T> 后代来处理我的应用程序中对象列表之间的通用功能。然后我想从那个新类中进一步下降,以便在需要时引入额外的功能。我似乎无法使用超过 1 级的继承来使其工作。我可能需要更多地了解泛型,但我已经从高处和低处搜索了正确的方法来做到这一点,但没有成功。到目前为止,这是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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

似乎有以下声明:

1
>>> TCatalogueItemList = class(TIndexedObjectList<TCatalogueItem>) <<<<

导致以下编译器错误:

[DCC Error] edGenerics.pas(106): E2010 Incompatible types:
'TCatalogueItem' and 'TIndexedObject'

但是编译器在编译单元的末尾(第 106 行)显示错误,而不是在声明本身上,这对我来说没有任何意义...

基本上我的想法是我有一个从 TObjectList 下降的通用列表,我可以根据需要扩展新功能。对此的任何帮助都会很棒!!!

我应该使用 Delphi 2010 添加。

谢谢。


您的错误在于类型转换,编译器错误是可以的(但它无法在我的 Delphi XE3 中找到正确的文件)。

您的 ItemByIndex 方法已声明:

1
TIndexedObjectList< T >.ItemByIndex(AIndex: Integer): T;

但是你有这行:

1
Result := TIndexedObject(nil);

这对于父类 TIndexedObjectList 来说很好,其中函数的结果是 TIndexedObject 类型,但对于子类 TCatalogueItemList 来说是不行的,其中函数的结果是类型 TCatalogueItem.

您可能知道,TCatalogueItem 实例是与 TIndexedObject 变量兼容的赋值,但反之则不然。它翻译成这样的:

1
2
3
function TCatalogueItemList.ItemByIndex(AIndex: Integer): TCatalogueItem;
begin
  Result := TIndexedObject(nil);  //did you see the problem now?

要将结果初始化为 nil 值,可以调用 Default() 伪函数,如下所示:

1
Result := Default(T);

在 Delphi XE 或更高版本中,该解决方案也是通用的。不是将结果类型转换为固定的 TIndexedObjectList 类,而是使用 T 类型

应用泛型类型转换

1
2
3
Result := T(nil);
//or
Result := T(SomeOtherValue);

但是,在这种特定情况下,不需要对 nil 常量进行类型转换,因为 nil 是一个与任何引用兼容的特殊值,因此您只需将行替换为:

1
Result := nil;

它会编译,并希望能像你期望的那样工作。