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

时间:2018-12-15 15:15:17

标签: 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;

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.

1 个答案:

答案 0 :(得分:4)

您需要两次解析function GetCurrent: T:对于IDataList<T>Enumerator<T>但对于IEnumerator<T>的非通用祖先,您还需要一个:IEnumerator 。显然,GetCurrent的{​​{1}}方法并没有隐藏这一点。

尝试method resolution clauses

IEnumerator<T>

两者的实现可以相同,但是您将必须使用两种方法。非通用function GetGenericCurrent: T; // implement this function IDataList<T>.GetCurrent = GetGenericCurrent; function IEnumerator<T>.GetCurrent = GetGenericCurrent; function GetCurrent: TObject; // implement this -- can return nil. 的那个可以返回IEnumerator


更新

我不得不修改上面的代码。现在应该可以了。 nil返回GetCurrent并不需要有两个实现,但是返回T时必须具有一个实现。