5

データセット内のレコードを Delphi のプレジェネリック バージョンの Delphi レコードに変換するインターフェイスを実装しようとしています。現時点ではインターフェイスが好きではありません.可能な限り避けたいサポートへの呼び出しが常に必要であり、私が見逃しているより良い方法があるかどうか疑問に思っていました.

これまでのところ、ナビゲーション インターフェイスとデータ取得インターフェイスが定義されています。

IBaseRecordCollection = interface
  procedure First;
  procedure Next;
  function BOF: boolean;
  ... // other dataset nav stuff
end;

IRecARecordCollection = interface
  function GetRec: TRecA;
end;

IRecBRecordCollection = interface
  function GetRec: TRecB;
end;

基本的に、プライベート データセットを含む具体的な基本クラスがあり、IBaseRecordCollectionRecordCollection インターフェイスごとに具象クラスが実装されています。これは、レコード取得ルーチンの実装を使用してIBaseRecordCollection(プロパティによって処理される) を実装する抽象クラスから派生します。implements

TAbstractTypedRecordCollection = class(TInterfacedObject, IBaseRecordCollection)
private
  FCollection: IBaseRecordCollection;
protected
  property Collection: IBaseRecordCollection read FCollection implements IBaseRecordCollection;
public
  constructor Create(aRecordCollection: IBaseRecordCollection);
end;

TRec1RecordCollection = class(TAbstractTypedRecordCollection, IRecARecordCollection);
public
  function GetRec: TRecA;
end;

IRecARecordCollectionさて、これを使用するには、 a を返してから をいじるビルダーを用意する必要がありますSupports

すなわち

procedure GetMyRecASet;
var
  lRecARecordCollection: IRecARecordCollection;
  lRecordCollection: IBaseRecordCollection;
begin
  lRecARecordCollection := BuildRecACollection;
  if not supports(lRecARecordCollection, IBaseRecordCollection, lRecordCollection) then 
     raise exception.create();
  while not lRecordCollection.EOF do
  begin
    lRecARecordCollection.GetRec.DoStuff;
    lRecordCollection.Next;
  end;
end;

これはうまくいきますが、私は呼び出しに熱心ではなく、supportsこのように lRecordCollections と lRecARecordCollections を混合します。私はもともと次のようなことができることを望んでいました:

IBaseRecordCollection = interface
  // DBNav stuff
end;

IRecARecordCollection = interface (IBaseRecordCollection)
  function GetRec: TRecA;
end;

TRec1RecordCollection = class(TInterfacedObject, IRecARecordCollection)
private
  FCollection: IBaseRecordCollection;
protected
  property Collection: IBaseRecordCollection read FCollection implements IBaseRecordCollection;
public
  function GetRec: TRecA;
end;

IBaseRecordCollectionしかし残念なことに、Delphi は IRecARecordCollection の実装がCollection プロパティのimplements呼び出しと TRec1RecordCollection オブジェクトのベースで分割されていることに気付くほど賢くありませんでした。

これを実現するためのより適切な方法について他に提案はありますか?

-- @David の回答に対して、コメントよりも (長い) 返信をするように編集します。

提案された解決策:

IBaseRecordCollection = interface ['{C910BD0A-26F4-4682-BC82-605C4C8F9173}']
  function GetRecNo: integer;
  function GetRecCount: integer;
  function GetFieldList: TFieldList;
  function EOF: boolean;
  function BOF: boolean;
  ...
end;

IRec1RecordCollection = interface (IBaseRecordCollection) ['{E12F9F6D-6D57-4C7D-AB87-8DD50D35DCA2}']
  function GetRec: TRec1;
  property Rec: TRec1 read GetRec;
end;

TAbstractTypedRecordCollection = class(TInterfacedObject, IBaseRecordCollection)
private
  FCollection: IBaseRecordCollection;
protected
  property Collection: IBaseRecordCollection read FCollection implements IBaseRecordCollection;
public
  constructor Create(aRecordCollection: IBaseRecordCollection);
end;

TRec1RecordCollection = class(TAbstractTypedRecordCollection, IRec1RecordCollection, IBaseRecordCollection)
private
  function GetRec: TRec1;
public
  property Rec: TRec1 read GetRec;
end;

コンパイルしていません。TRec1RecordCollectionに関連するメソッドが見つからないと不平を言っていますIBaseRecordCollectionCollectionまた、プロパティを Abstract から移動して、すべて同じ結果でRec1RecordCollectionプロパティを再宣言しようとしましたTRec1RecordCollection

もう少し深く見てみると、実装するクラスの直接継承は機能するように見えますIBaseRecordCollectionが、Delphi は を使用してプロパティを介して間接的に継承することを処理できませんimplements

4

1 に答える 1

7

あなたのコードはほとんどそこにあります。クラスが派生インターフェイスを実装することのみを宣言したため、コード内の implements ディレクティブはコンパイルに失敗します。現状では、あなたのクラスは、implements ディレクティブが参照するインターフェイス、つまり を実装していませんIBaseRecordCollection。継承から推測されると思うかもしれませんが、そうではありません。

TRec1RecordCollection問題を解決するには、両方のインターフェースを実装することを宣言するだけです:

type
  TRec1RecordCollection = class(TInterfacedObject, IBaseRecordCollection, 
    IRecARecordCollection)
  ....
  end;

小さな変更を 1 つ加えるだけで、コードがコンパイルされます。

アップデート

質問への編集により、これが多少変更されます。元の質問のコードを考えると、私の答えのコードは実際にコンパイルされます。ただし、にメソッドを追加するIBaseRecordCollectionと、コンパイルはそれを受け入れません。

コンパイラはこのコードを受け入れる必要がありますが、そうでないのはコンパイラのバグが原因です。Delphi の最新バージョンは、質問に対する更新のコードを受け入れます。

コンパイラをアップグレードしない限り、意図した設計を機能させることはできません。

于 2013-09-27T16:20:59.347 に答える