草庐IT

Delphi 泛型 TObjectList< T > 继承

codeneng 2023-03-28 原文

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 添加。

谢谢。

  • 如果您能指出导致错误的代码的实际部分,那就太好了(因为您可以使用它)。这比期望我们计算或复制/粘贴到编辑器中要容易得多。像 // error happens here//this is line 106 这样的简单注释就足够了。
  • 对问题主体添加了进一步的解释
  • TIndexedObjectList<T: TIndexedObject> 不应该像您当前的代码那样从 TObjectBaseList<T: TObjectBase> 而不是从 TObjectList<T> 下降吗?
  • 是的,它应该感谢您选择它。但是,在对声明进行更正后,它与之前的编译错误完全相同。
  • @Ken:XE3 IDE 将错误定位在文件的最后一行(最后一行之后)。错误消息中没有提供行号。


您的错误在于类型转换,编译器错误是可以的(但它无法在我的 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;

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

  • 非常感谢您的回答。它几乎可以工作,但行:Result := nil 导致编译错误 Incompatible types: 'T' and 'Pointer'。这就是为什么我之前将它类型转换为 TIndexedObject。如何将泛型类型的 Result 设置为 nil 或泛型等效项?
  • 在 XE3 中它可以工作,但如果您的编译器需要强制转换,请使用通用的:Result := T(nil);,如答案中所述。
  • 感谢您的建议,但不幸的是,在 Delphi 2010 中,语句 Result := T(nil); 会产生 Invalid typecast 错误。因此,这两种方法似乎都不适用于 Delphi 2010。有趣的是,如果我完全注释掉该行,它编译时不会出错。我将进一步对此进行测试,以查看当项目不在列表中时它是否返回 nil。
  • 在 Delphi 2010 中(也许以后?),为函数结果初始化泛型类型的正确方法是 Result := Default(T);。这似乎适用于上述功能。
  • @Rick 和 jachguate:感谢 Default(T)。学到了一些新东西。
  • @MarjanVenema 你没有注意。我们在这里每隔一周介绍一次Default(T)
  • @DavidHeffernan:哦,亲爱的,我被抓到了吗?一直忙于其他事情,不要像我一样关注SO...

有关Delphi 泛型 TObjectList< T > 继承的更多相关文章

  1. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  2. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  3. ruby-on-rails - Nokogiri:使用 XPath 搜索 <div> - 2

    我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll

  4. ruby-on-rails - Rails 单表继承 : How to override the value written to the type field - 2

    在我的系统中,我已经定义了STI。Dog继承自Animal,在animals表中有一个type列,其值为"Dog"。现在我想让SpecialDog继承自dog,只是为了在某些特殊情况下稍微修改一下行为。数据还是一样。我需要通过SpecialDog运行的所有查询,以返回数据库中类型为Dog的值。我的问题是因为我有一个type列,rails将WHERE"animals"."type"IN('SpecialDog')附加到我的查询中,所以我不能获取原始的Dog条目。所以我想要的是以某种方式覆盖rails在通过SpecialDog访问数据库时使用的值,使其表现得像Dog。有没有办法覆盖用于类型

  5. ruby-on-rails - 没有参数的 `<<`(小于两倍)是什么意思? - 2

    我在一个我想在formtasticGem中覆盖的方法中找到了这个。该方法如下所示:defto_htmlinput_wrappingdohidden_field_html是什么意思?在第三行做什么?我知道它对数组有什么作用,但在这里我不知道。 最佳答案 你可以这样读:hidden_field_htmllabel_with_nested_checkbox是连接到hidden_​​field_html末尾的参数-为了“清晰”,他们将其分成两行 关于ruby-on-rails-没有参数的`

  6. ruby-on-rails - 找不到 gem railties (>= 0.a) (Gem::GemNotFoundException) - 2

    我已经看到了一些其他的问题,尝试了他们的建议,但没有一个对我有用。我已经使用Rails大约一年了,刚刚开始一个新的Rails项目,突然遇到了问题。我卸载并尝试重新安装所有Ruby和Rails。Ruby很好,但Rails不行。当我输入railss时,我得到了can'tfindgemrailties。我当前的Ruby版本是ruby2.2.2p95(2015-04-13修订版50295)[x86_64-darwin15],尽管我一直在尝试通过rbenv设置ruby​​2.3.0。如果我尝试rails-v查看我正在运行的版本,我会得到同样的错误。我使用的是MacOSXElCapitan版本10

  7. ruby-on-rails - 连接字符串时如何在 <%=%> block 内输出 html_safe? - 2

    考虑一下:现在这些情况:#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2我需要用其他字符串输出URL。我如何保证&符号不会被转义?由于我无法控制的原因,我无法发送&。求助!把我的头发拉到这里:\编辑:为了澄清,我实际上有一个像这样的数组:@images=[{:id=>"fooid",:url=>"http://

  8. Ruby -> 写入二维数组 - 2

    我正在处理http://prepwork.appacademy.io/mini-curriculum/array/中概述的数组问题我正在尝试创建函数my_transpose,它接受一个矩阵并返回其转置。我对写入二维数组感到很困惑!这是一个代码片段,突出了我的困惑。rows=[[0,1,2],[3,4,5],[6,7,8]]columns=Array.new(3,Array.new(3))putscolumns.to_s#Outputisa3x3arrayfilledwithnilcolumns[0][0]=0putscolumns.to_s#Outputis[[0,nil,nil],[

  9. ruby - 为什么必须明确指定 2 个参数才能 curry :> - 2

    考虑这个,它工作正常::>.to_proc.curry(2)[9][8]#=>true,because9>8然而,即使>是一个二元运算符,如果没有指定的元数,上面的代码将无法工作::>.to_proc.curry[9][8]#=>ArgumentError:wrongnumberofarguments(0for1)为什么两者不等价?注意:我特别想用提供的一个参数创建中间柯里化(Currying)函数,然后然后调用然后用第二个参数调用它。 最佳答案 curry必须知道传入的过程的数量,对吧?:-1来自arity的负值令人困惑,但基本上

  10. ruby-on-rails - 为什么 DataMapper 使用混合与继承? - 2

    所以我只是对此感到好奇:DataMapper为其模型使用混合classPostincludeDataMapper::Resource虽然active-record使用继承classPost有谁知道为什么DataMapper选择这样做(或者为什么AR选择不这样做)? 最佳答案 它允许您从另一个不是DM类的类继承。它还允许动态地将DM功能添加到类中。这是我正在处理的模块中的类方法:defdatamapper_classklass=self.dupklass.send(:include,DataMapper::Resource)klass

随机推荐