Компилятор не отображает метод класса на метод интерфейса - PullRequest
0 голосов
/ 15 декабря 2018

Я использую Delphi Pro 10.2.3 Tokyo.Я хочу создать класс-оболочку TDataset, который я могу использовать для перечисления в списке потомков IData с циклом for-in.Когда я пытаюсь скомпилировать приведенный ниже код, я получаю следующее сообщение об ошибке:

[ошибка 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 голосов
/ 15 декабря 2018

Вам нужно разрешить function GetCurrent: T дважды: для IDataList<T> и для Enumerator<T>. Но вам также нужен один для неуниверсального предка IEnumerator<T>: IEnumerator.Очевидно, что это не скрыто методом GetCurrent 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, но у вас должна быть одна, возвращающая TObject.

...