我正在尝试创建一个与tiOPF(delphi @ www.tiopf.com的对象持久性框架)一起使用的通用列表类。具体来说,我试图采用现有的泛型类(TtiObjectList)并制作使用TtiObject后代的通用版本。
由于需要在D7-D2009和Free Pascal下编译,因此我更改了基类的范围有限。我需要从TtiObjectList继承,以保持现有的持久性机制。
// base class
type
TtiObjectList = class(TtiObject)
...
protected
function GetItems(i: integer): TtiObject; virtual;
procedure SetItems(i: integer; const AValue: TtiObject); virtual;
...
public
function Add(const AObject : TtiObject): integer; overload; virtual;
...
end;
我的课程定义如下:
TtiGenericObjectList<T: TtiObject> = class(TtiObjectList)
protected
function GetItems(i:integer): T; reintroduce;
procedure SetItems(i:integer; const Value: T); reintroduce;
public
function Add(const AObject: T): integer; reintroduce;
property Items[i:integer]: T read GetItems write SetItems; default;
end;
implementation
{ TtiGenericObjectList<T> }
function TtiGenericObjectList<T>.Add(const AObject: T): integer;
var obj: TtiObject;
begin
obj:= TtiObject(AObject); /// Invalid typecast
result:= inherited Add(obj);
end;
// alternate add, also fails
function TtiGenericObjectList<T>.Add(const AObject: T): integer;
begin
result:= inherited Add(AObject); /// **There is no overloaded version**
/// **of 'Add' that can be called with these arguments**
end;
function TtiGenericObjectList<T>.GetItems(i: integer): T;
begin
result:= T(inherited GetItems(i)); /// **Invalid typecast **
end;
procedure TtiGenericObjectList<T>.SetItems(i: integer; const Value: T);
begin
inherited SetItems(i, Value);
end;
我遇到的问题是delphi没有将T视为TtiObject后代。当我执行以下操作时,我收到无效的类型转换错误:
function TtiGenericObjectList<T>.Add(const AObject: T): integer;
var obj: TtiObject;
begin
obj:= TtiObject(AObject); /// **Invalid typecast***
result:= inherited Add(obj);
end;
如果我不进行类型转换,那么我会收到过载错误,如上面的清单所示。
我出错的任何想法?
肖恩
答案 0 :(得分:2)
Delphi 2009编译器在其泛型实现中存在一些非常严重的缺陷。它几乎不应该理解约束的含义,(Barry Kelly在SO的其他地方承认了这一点;我不记得究竟在哪里),并且跨单元泛型会引起非常奇怪的问题。最好的办法是根据具体情况处理这个:如果您的代码编译,请使用它。如果没有,请返回非通用实现,直到修复它为止。希望我们能在不久的将来看到更新修复泛型(以及Generics.Collections单元)。
答案 1 :(得分:2)
看起来问题不是我,而是编译器:)。
最后,我使用以下方法攻击它
class function TtiGenericObjectList<T>.GenericAsObject(const Value): TObject;
begin
Result := TObject(Value);
end;
class function TtiGenericObjectList<T>.ObjectAsGeneric(const Value): T;
begin
Result := T(Value);
end;
使用如下
function TtiGenericObjectList<T>.Add(const AObject: T): integer;
var obj: TtiObject;
begin
obj:= TtiObject(GenericAsObject(AObject));
result:= inherited Add(obj);
// replaces the following which gets overload errors
// result:= inherited Add(TtiObject(AObject));
end;
和
function TtiGenericObjectList<T>.GetItems(i: integer): T;
var obj: TtiObject;
begin
obj:= inherited GetItems(i);
result:= ObjectAsGeneric(obj);
// replaces the following which gets "Invalid typecast" errors
// result:= inherited Add(AObject);
end;
我会稍微清理一下并使用它们,直到编译器得到修复。
答案 2 :(得分:1)
我最近使用D2010处理了类似的问题,这是我提出的代码。
type
TGenericList<T: TtiObject> = class(TtiObjectList)
protected
function GetItems(AIndex: integer): T; reintroduce;
procedure SetItems(AIndex: integer; const AValue: T); reintroduce;
public
property Items[i:integer]: T read GetItems write SetItems; default;
function Add(const AObject: T): integer; reintroduce;
end;
implementation
{ TGenericList<T> }
function TGenericList<T>.Add(const AObject: T): integer;
begin
Result := inherited Add(TtiObject(AObject));
end;
function TGenericList<T>.GetItems(AIndex: integer): T;
begin
Result := T(inherited GetItems(AIndex));
end;
procedure TGenericList<T>.SetItems(AIndex: integer; const AValue: T);
begin
inherited SetItems(AIndex, AValue);
end;
答案 3 :(得分:0)
我发现了一些关于泛型的小问题,这对于这样一个新功能来说并不奇怪。而你正试图真正地混淆编译器; - )。
不幸的是我手边没有2009年,所以我无法测试,但我有一些建议:
您是否已查找更新(并已安装)?
您是否尝试过使用as和is运算符:
obj:= AObject as TtiObject;
您是否尝试过使用中级课程:
TtiGenericList<T: TObject> = class(TtiObjectList)
protected
function GetItems(i:integer): T; reintroduce;
procedure SetItems(i:integer; const Value: T); reintroduce;
public
function Add(const AObject: T): integer; reintroduce;
property Items[i:integer]: T read GetItems write SetItems; default;
end;
答案 4 :(得分:0)
(由于类似的问题我来到这里,但在确定它的同时我得到了一个不同的解决方案,但是使用了更新的(XE)Delphi):
或者只是尝试将类型为T.
的局部变量 Obj