Delphi Generic constraints problem

南楼画角 提交于 2019-12-04 17:55:05

The Delphi 2009 compiler has a few very serious flaws in its generics implementation. It doesn't understand the implications of constraints nearly as well as it ought to, (Barry Kelly admitted this somewhere else on SO; I don't remember exactly where,) and cross-unit generics can cause very strange problems. Best bet is to handle this one on a case-by-case basis: If your code compiles, use it. If not, go back to a non-generic implementation until they get it fixed. Hopefully we'll see an update that fixes generics (and the Generics.Collections unit) sometime in the near future.

It looks like the problem is not me, but the compiler :).

In the end, I have hacked around it using the following methods

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;

used as follows

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;

and

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;

I will clean these up a bit and use them till the compiler gets fixed.

I recently tackled a similar problem using D2010, and here is the code I came up with.

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;

I have found some little issues with generics, which is not surprising for such a new feature. And you are trying to confuse the compiler real hard ;-).

Unfortunately I have no 2009 at hand here so I can't test, but I have some suggestions:

Have you looked for updates (and installed them)?

Have you tried using the as and is operators:

obj:= AObject as TtiObject;

Have you tried using an intermediate class:

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;

(I got here due to a similar problem, but while nailing it down I got to a different solution, though with a newer(XE) Delphi):

Or simply try to make that local variable Obj of type T.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!