【问题标题】:Interface inheritance without generics没有泛型的接口继承
【发布时间】:2013-10-04 00:49:49
【问题描述】:

我正在尝试实现一个接口,以将数据集中的记录转换为 Delphi 的预泛型版本中的 Delphi 记录。目前我不喜欢这个界面,因为它总是需要调用 Supports,如果可能的话我想避免这种情况,并且想知道是否有更好的方法可以做到这一点。

到目前为止,我已经定义了导航界面和数据检索界面:

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;

基本上,我有一个具体的基类,它包含一个私有数据集并为每个 RecordCollection 接口实现IBaseRecordCollection 和具体类,该接口派生自实现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 的构建器,然后乱用 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;

但不幸的是,Delphi 不够聪明,无法意识到 IRecARecordCollection 的实现被拆分为 Collection 属性 implements 调用中的基础 IBaseRecordCollection 和 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 找不到与IBaseRecordCollection 相关的方法。我还尝试将 Collection 属性从 Abstract 移动到 Rec1RecordCollection 并在 TRec1RecordCollection 中重新声明该属性,结果都相同

看起来更深入一点,实现 IBaseRecordCollection 的类的直接继承似乎可以工作,但 Delphi 无法通过使用 implements 的属性间接地处理它。

【问题讨论】:

  • 为了完整起见,由于 D2006 编译器中似乎存在一个错误(A 错误????),这意味着下面的@David 的解决方案不起作用我有必须砍掉依赖注入,只让所有 TRecXRecordCollections 从具体的 TBaseRecordCollection 继承而不是 TAbstractTypedRecordCollection

标签: delphi inheritance interface delphi-2006


【解决方案1】:

您的代码几乎就在那里。您的代码中的 implements 指令无法编译,因为您只声明您的类实现了派生接口。就目前而言,您的类没有实现 implements 指令所指的接口,即IBaseRecordCollection。您可能认为这会从继承中推断出来,但事实并非如此。

要解决您的问题,您只需声明TRec1RecordCollection 实现了这两个接口:

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

只需进行一点小改动,您的代码就会编译成功。

更新

您对问题的编辑对此有所改变。鉴于您原始问题中的代码,我的答案中的代码确实可以编译。但是,将任何方法添加到IBaseRecordCollection 中,编译器将不接受它。

编译器应该接受此代码,而它不接受的事实是因为编译器错误。现代版本的 Delphi 将接受您对问题的更新中的代码。

除非您升级您的编译器,否则您将无法使您的预期设计工作。

【讨论】:

  • 是的,但是我必须传递具体的实现而不是接口,确定吗?这不是否定了我们试图通过接口实现的目标吗?将它与两个接口一起应用仍然会导致上面的supports 代码,我从构建器中获取一个接口,并且必须使用Supports 来获取另一个接口,而这正是我试图避免的。
  • 不,绕过 IRecARecordCollection
  • 太棒了 - 我会在星期一回到办公室时试一试,如果它有效,我会接受
  • 查看上述问题的编辑 - 简短版:它没有编译
  • 对,现在你问的是不同的问题。鉴于原始问题中的代码,我的答案中的代码可以编译。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-27
  • 1970-01-01
  • 2014-03-05
  • 1970-01-01
  • 2011-06-14
  • 1970-01-01
相关资源
最近更新 更多