Delphi 编译器未将类方法映射到接口方法

Delphi 编译器未将类方法映射到接口方法,delphi,enumeration,Delphi,Enumeration,我正在使用Delphi Pro 10.2.3 Tokyo。我想创建一个TDataset包装类,我可以使用它来枚举带有for in循环的IData子体列表。当我试图编译下面的代码时,我得到以下错误消息 [dcc32错误]Core.Data.DatasetAdapter.pas(25):E2291缺少接口方法IEnumerator.GetCurrent的实现 显然,GetCurrent已经实现。你知道怎么解决这个问题吗 unit Core.Data.DatasetAdapter; interfac

我正在使用Delphi Pro 10.2.3 Tokyo。我想创建一个TDataset包装类,我可以使用它来枚举带有for in循环的IData子体列表。当我试图编译下面的代码时,我得到以下错误消息

[dcc32错误]Core.Data.DatasetAdapter.pas(25):E2291缺少接口方法IEnumerator.GetCurrent的实现

显然,GetCurrent已经实现。你知道怎么解决这个问题吗

unit Core.Data.DatasetAdapter;

interface

uses
    Data.Db
  ;

type
  IData = interface
    ['{15D1CF4F-B9E1-4525-B035-24B9A6584325}']
  end;

  IDataList<T: IData> = interface
    ['{9FEE9BB1-A983-4FEA-AEBF-4D3AF5219444}']
    function GetCount: Integer;
    function GetCurrent: T;
    procedure Load;
    procedure Unload;
    property Count: Integer read GetCount;
    property Current: T read GetCurrent;
  end;

  TDatasetAdapter<T: IData> = class(
      TInterfacedObject
    , IData, IDataList<T>
    , IEnumerator<T>
  )
  private
    FBof: Boolean;
    FDataset: TDataset;
    FIntf: T;
    function GetCount: Integer;
    function GetCurrent: T;
    function GetEof: Boolean;
    function GetInterface: T;
    function MoveNext: Boolean;
    procedure Reset;
  protected
    function FieldByName(const FieldName: string): TField;
    procedure MapFields; virtual;
    property Dataset: TDataset read FDataset;
  public
    constructor Create(ADataset: TDataset); virtual;
    function GetEnumerator: IEnumerator<T>;
    procedure Cancel;
    procedure Close;
    procedure Delete;
    procedure Edit;
    procedure First;
    procedure Insert;
    procedure Load;
    procedure Next;
    procedure Open;
    procedure Post;
    procedure UnLoad;
    property Count: Integer read GetCount;
    property Eof: Boolean read GetEof;
  end;

implementation

uses

    System.SysUtils
  , System.TypInfo
  ;

{ TDatasetAdapter<T> }

{
****************************** TDatasetAdapter<T> ******************************
}
constructor TDatasetAdapter<T>.Create(ADataset: TDataset);
begin
  FDataset := ADataset;
  FIntf    := GetInterface;
end;

procedure TDatasetAdapter<T>.Cancel;
begin
  FDataset.Cancel;
end;

procedure TDatasetAdapter<T>.Close;
begin
  FDataset.Close;
end;

procedure TDatasetAdapter<T>.Delete;
begin
  FDataset.Delete;
end;

procedure TDatasetAdapter<T>.Edit;
begin
  FDataset.Edit;
end;

function TDatasetAdapter<T>.FieldByName(const FieldName: string): TField;
begin
  Result := FDataset.FieldByName(FieldName);
end;

procedure TDatasetAdapter<T>.First;
begin
  FDataset.First;
end;

function TDatasetAdapter<T>.GetCount: Integer;
begin
  Result := FDataset.RecordCount;
end;

function TDatasetAdapter<T>.GetCurrent: T;
begin
  Result := FIntf;
end;

function TDatasetAdapter<T>.GetEnumerator: IEnumerator<T>;
begin
  Reset;
  Result := Self;
end;

function TDatasetAdapter<T>.GetEof: Boolean;
begin
  Result := FDataset.Eof;
end;

function TDatasetAdapter<T>.GetInterface: T;
var
  LGuid: TGuid;
begin
  LGuid := GetTypeData(TypeInfo(T))^.Guid;
  if not Supports(Self, LGuid, Result) then
    Result := nil;
end;

procedure TDatasetAdapter<T>.Insert;
begin
  FDataset.Insert;
end;

procedure TDatasetAdapter<T>.Load;
begin
  Open;
  MapFields;
end;

procedure TDatasetAdapter<T>.MapFields;
begin
  //Stub procedure
end;

function TDatasetAdapter<T>.MoveNext: Boolean;
begin
  if FBof then FBof := False
  else         Next;
  Result := not Eof;
end;

procedure TDatasetAdapter<T>.Next;
begin
  FDataset.Next;
end;

procedure TDatasetAdapter<T>.Open;
begin
  FDataset.Open;
end;

procedure TDatasetAdapter<T>.Post;
begin
  FDataset.Post;
end;

procedure TDatasetAdapter<T>.Reset;
begin
  FBof := True;
  First;
end;

procedure TDatasetAdapter<T>.UnLoad;
begin
  Close;
end;

end.
unit Core.Data.DatasetAdapter;
接口
使用
Data.Db
;
类型
IData=接口
[{15D1CF4F-B9E1-4525-B035-24B9A6584325}]
结束;
IDataList=接口
[{9FEE9BB1-A983-4FEA-AEBF-4D3AF521944}]
函数GetCount:Integer;
函数GetCurrent:T;
程序负载;
程序卸载;
属性计数:整数读取GetCount;
属性当前:T读取GetCurrent;
结束;
TDatasetAdapter=class(
着色面对象
,IData,IDataList
,IEnumerator
)
私有的
FBof:布尔型;
FDataset:TDataset;
FIntf:T;
函数GetCount:Integer;
函数GetCurrent:T;
函数GetEof:Boolean;
函数GetInterface:T;
函数MoveNext:布尔;
程序复位;
受保护的
函数FieldByName(常量FieldName:string):t字段;
程序映射域;事实上的
属性数据集:TDataset读取FDataset;
公众的
构造函数创建(ADataset:TDataset);事实上的
函数GetEnumerator:IEnumerator;
程序取消;
程序关闭;
程序删除;
程序编辑;
程序优先;
程序插入;
程序负载;
下一步程序;
程序开放;
程序岗;
程序卸载;
属性计数:整数读取GetCount;
属性Eof:布尔读取GetEof;
结束;
实施
使用
System.SysUtils
,System.TypInfo
;
{TDatasetAdapter}
{
******************************TDatasetAdapter******************************
}
构造函数TDatasetAdapter.Create(ADataset:TDataset);
开始
FDataset:=ADataset;
FIntf:=GetInterface;
结束;
程序TDatasetAdapter.Cancel;
开始
FDataset.Cancel;
结束;
程序TDatasetAdapter.Close;
开始
FDataset.Close;
结束;
程序TDatasetAdapter.Delete;
开始
FDataset.Delete;
结束;
程序TDatasetAdapter.Edit;
开始
FDataset.Edit;
结束;
函数TDatasetAdapter.FieldByName(const FieldName:string):TField;
开始
结果:=FDataset.FieldByName(FieldName);
结束;
程序TDatasetAdapter。首先;
开始
FDataset.First;
结束;
函数TDatasetAdapter.GetCount:整数;
开始
结果:=FDataset.RecordCount;
结束;
函数TDatasetAdapter.GetCurrent:T;
开始
结果:=FIntf;
结束;
函数TDatasetAdapter.GetEnumerator:IEnumerator;
开始
复位;
结果:=自我;
结束;
函数TDatasetAdapter.GetEof:Boolean;
开始
结果:=FDataset.Eof;
结束;
函数TDatasetAdapter.GetInterface:T;
变量
LGuid:TGuid;
开始
LGuid:=GetTypeData(TypeInfo(T))^.Guid;
如果不支持(Self、LGuid、Result),则
结果:=无;
结束;
程序TDatasetAdapter.Insert;
开始
FDataset.Insert;
结束;
程序TDatasetAdapter.Load;
开始
打开
地图场;
结束;
程序TDatasetAdapter.MapFields;
开始
//存根程序
结束;
函数TDatasetAdapter.MoveNext:布尔值;
开始
如果FBof,则FBof:=假
下一步;
结果:=非Eof;
结束;
程序TDatasetAdapter.Next;
开始
FDataset.Next;
结束;
程序TDatasetAdapter.Open;
开始
FDataset.Open;
结束;
程序TDatasetAdapter.Post;
开始
FDataset.Post;
结束;
程序TDatasetAdapter.Reset;
开始
FBof:=真;
第一;
结束;
程序TDatasetAdapter.UnLoad;
开始
接近;
结束;
结束。

您需要两次解析
函数GetCurrent:T
:对于
IDataList
和对于
枚举器
但对于
IEnumerator
IEnumerator
的非泛型祖先也需要一个。显然,
IEnumerator
GetCurrent
方法并没有隐藏这一点

尝试:

函数GetGenericCurrent:T;//实施这个 函数IDataList.GetCurrent=GetGenericCurrent; 函数IEnumerator.GetCurrent=GetGenericCurrent; 函数GetCurrent:ToObject;//实现这个——可以返回nil。 这两种方法的实现可以是相同的,但您必须创建两种方法。非泛型的
IEnumerator
可以返回
nil


更新
我不得不修改上面的代码。现在应该可以了。对于返回的
T
,不必有两个实现,但必须有一个实现返回
TObject

我想知道错误是否应该改为“缺少接口方法IEnumerator.GetCurrent的实现”@sertac-akyuz我直接从IDE消息框复制并粘贴了该消息。@sertac:no,因为该消息已实现。显然,从
IEnumerator
(非泛型)继承的返回
TObject
,不会被返回
T
的新对象隐藏。返回
TObject
的方法也必须实现。看到我的答案了。joeb,是的,我想知道为什么编译器会抱怨,当你实现的是IEnumerator时,但多亏了@Rudy,现在它才有意义。真的。我希望一个方法和一个方法解决条款就足够了。@rudy veltuis我同意David的观点。我将IDataList.GetCurrent重命名为IDataList.GetItem,并使用方法解析子句映射IEnumerator.GetCurrent。收到相同的错误消息。无论如何,我修改了我的答案。我忘了为非泛型
IEnumerator
提供一个版本。当然,这就是错误消息所说的。大卫:我不确定这封信是否区分了IEnumerator和IEnumerator。我甚至还尝试了非泛型IEnumerator的方法解析子句,但随后会出现另一条消息,因为IEnumerator不是显式的o部分
function GetGenericCurrent: T; // implement this
function IDataList<T>.GetCurrent = GetGenericCurrent;
function IEnumerator<T>.GetCurrent = GetGenericCurrent;
function GetCurrent: TObject; // implement this -- can return nil.