Ошибка компиляции использования универсального класса Delphi - PullRequest
0 голосов
/ 08 ноября 2019

Я пишу некоторый служебный код для старой кодовой базы Delphi XE;чтобы сделать вещи проще и безопаснее, я создал метод, предназначенный для переноса специфичного для типа TProc<TReq> (где TReq - универсальный тип класса), передаваемого через параметры в более широкий TProc<TObject>, который должен быть передан всторонний компонент позже, вместе с TClass(TReq) и дополнительным строковым аргументом:

type
  TREvoHostConnectionOptions = record
    // [...]
    procedure OnPush<TReq:class>(const pushMethod: string; const action: TProc<TReq>);
  end;

// [...]

procedure TREvoHostConnectionOptions.OnPush<TReq>(const pushMethod: string; const action: TProc<TReq>);
    var
      rec: TRPushHandler;
    begin
      rec.PushMethod := pushMethod;
      rec.PushModel := TClass(TReq);
      rec.Handler :=
        procedure(reqRawModel: TObject)
          var
            reqModel: TReq;
          begin
            // Conversione modello richiesta
            reqModel := reqRawModel as TReq;
            if Assigned(reqRawModel) and not Assigned(reqModel) then
              raise EEvoHostException.Create(Format('Impossibile convertire il modello di tipo %s in %s.', [reqRawModel.ClassName, TClass(TReq).ClassName]));
            // Azione
            if Assigned(action) then
              action(reqModel);
          end;
      PushHandlers.Add(rec);
    end;

Предыдущий метод успешно компилируется и, если вызывается так, работает как задумано (хотя, имея TObject какуниверсальный тип игнорирует цель метода):

opts.OnPush<TObject>('Test', procedure (reqModel: TObject) begin (* ... *) end);

Однако, если в модуле формы тестирования я вызываю его с помощью специально созданного класса модели:

  type
    TTestModel = class(TObject)
      strict private
        _a, _b: string;
      public
        property A: string read _a write _a;
        property B: string read _b write _b;
    end;

Я получаюследующая ошибка компилятора в совершенно не относящейся к делу строке (и совершенно другой и совершенно не связанный метод) в вызывающем модуле:

[Ошибка DCC] WndMain.pas (96): E2010 Несовместимые типы: 'TTestModel 'и' TObject '

* Смещение происходит только с этой конкретной ошибкой, если я ввожу искусственную синтаксическую ошибку где-либо еще втот же файл сообщается в правильной строке.


Есть мысли? Это ошибка компилятора, и если да, то есть ли способ ее обойти? К сожалению, я не могу удалить ограничение :class на метод, потому что в противном случае преобразование TClass(TReq), которое происходит внутри метода, вызывает (логически) еще одну ошибку компиляции о том, что TReq не является ограниченным классом или типом интерфейса.

1 Ответ

0 голосов
/ 08 ноября 2019

После дальнейшего исследования проблема, похоже, вызвана преобразованием as в методе, хотя об этом было сообщено в неправильном файле.

Изменение метода, как этот, решило эту проблему:

procedure TREvoHostConnectionOptions.OnPush<TReq>(const pushMethod: string; const action: TProc<TReq>);
    var
      rec: TRPushHandler;
    begin
      rec.PushMethod := pushMethod;
      rec.PushModel := TClass(TReq);
      rec.Handler :=
        procedure(reqRawModel: TObject)
          var
            reqModel: TReq;
          begin
            // Conversione modello richiesta
            if Assigned(reqRawModel) and not reqRawModel.ClassType.InheritsFrom(rec.PushModel) then
              raise EEvoHostException.CreateFmt('Impossibile convertire il modello di tipo %s in %s.', [reqRawModel.ClassName, rec.PushModel.ClassName]);
            // Azione
            if Assigned(action) then
              action(TReq(reqModel));
          end;
      PushHandlers.Add(rec);
    end;
...