2

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;  

私が抱えている問題は、デルファイが T を TtiObject の子孫として認識していないことです。次のようなことをすると、無効な型キャスト エラーが発生します。

function TtiGenericObjectList<T>.Add(const AObject: T): integer;  
var obj: TtiObject;  
begin  
  obj:= TtiObject(AObject); /// **Invalid typecast***
  result:= inherited Add(obj);  
end;  

型キャストを行わないと、上記のリストに示されているように、代わりにオーバーロード エラーが発生します。

私が間違っているアイデアはありますか?

ショーン

4

5 に答える 5

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;

これらを少しクリーンアップして、コンパイラが修正されるまで使用します。

于 2009-02-24T19:45:03.780 に答える
2

Delphi 2009 コンパイラには、ジェネリックの実装に非常に重大な欠陥がいくつかあります。制約の意味を十分に理解していません (Barry Kelly は SO の別の場所でこれを認めました。正確な場所は覚えていません)。クロスユニットジェネリックは非常に奇妙な問題を引き起こす可能性があります。最善の策は、これをケースバイケースで処理することです。コードがコンパイルされる場合は、それを使用してください。そうでない場合は、修正されるまで非汎用の実装に戻ります。近い将来、ジェネリック (および Generics.Collections ユニット) を修正する更新プログラムが公開されることを願っています。

于 2009-02-24T16:58:44.537 に答える
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;
于 2009-10-27T07:12:40.590 に答える
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;
于 2009-02-24T07:45:55.833 に答える
0

(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.

于 2013-03-28T11:34:56.643 に答える