WedX - журнал о программировании и компьютерных науках

Компилятор не отображает метод класса на метод интерфейса

Я использую Delphi Pro 10.2.3 Токио. Я хочу создать класс-оболочку 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.
15.12.2018

  • Интересно, не должна ли ошибка вместо этого сказать Отсутствует реализация метода интерфейса IEnumerator‹T›.GetCurrent. 15.12.2018
  • @sertac-akyuz Я скопировал и вставил сообщение прямо из фрейма сообщения IDE. 15.12.2018
  • @Sertac: нет, потому что это реализовано. По-видимому, тот, который унаследован от IEnumerator (не общий), возвращает TObject, не скрыт новым, возвращающим T. Тот, который возвращает TObject, тоже должен быть реализован. Смотрите мой ответ. 15.12.2018
  • joeb, да, мне было интересно, почему компилятор жаловался, что когда то, что вы реализовали, было IEnumerator‹T›, но благодаря @Rudy теперь это имеет смысл. 15.12.2018

Ответы:


1

Вам нужно разрешить 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.

15.12.2018
  • Действительно. Я ожидаю, что будет достаточно одного метода и одного пункта разрешения метода. 15.12.2018
  • @rudy-veltuis Я согласен с Дэвидом. Я переименовал IDataList.GetCurrent в IDataList.GetItem И использовал предложение разрешения метода для сопоставления IEnumerator.GetCurrent. Получите такое же сообщение об ошибке. 15.12.2018
  • Во всяком случае, я изменил свой ответ. Я забыл иметь версию для неуниверсального IEnumerator. 15.12.2018
  • Это то, что, конечно, говорит сообщение об ошибке. Как мы могли это пропустить. 15.12.2018
  • @ Дэвид: я не был уверен, различает ли сообщение IEnumerator‹T› и IEnumerator. И я даже пытался использовать пункты разрешения методов для неуниверсального IEnumerator, но тогда было бы другое сообщение, потому что IEnumerator явно не был частью списка реализации. Это единственный способ, которым это работает. 16.12.2018
  • @RudyVelthuis Я закодировал, как вы предложили. Код скомпилирован, но когда я попытался протестировать его в цикле for-in, я получил следующий код ошибки: [Ошибка dcc32] Tests.Core.Data.DatasetAdapter.pas(83): оператор for-in E2431 не может работать с тип коллекции «Core.Data.DatasetAdapter.IDataList‹Core.Data.DatasetAdapter.IData›», поскольку «Core.Data.DatasetAdapter.IDataList‹Core.Data.DatasetAdapter.IData›» не содержит члена для «GetEnumerator», или это недоступно 16.12.2018
  • @ joeb545: это еще один вопрос. Это было о IEnumerator.GetCurrent. 16.12.2018
  • @RudyVelthuis Я понял это. Мне нужно было добавить GetEnumerator: IEnumerator‹T› в IDataList‹T›. Спасибо за решение! 16.12.2018
  • Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    Для любых предложений по сайту: [email protected]