Delphi 10.2 Tokyo — объект приведения, предоставляемый интерфейсом

Я пытаюсь преобразовать свое приложение с Delphi XE8 в 10.2 Tokyo. Я получаю странные исключения во время выполнения с объектами приведения, предоставляемыми интерфейсом через пакеты crocss (bpl). когда я пытаюсь преобразовать объекты с ключевым словом as, я получаю это исключение во время выполнения:

Project Project1.exe поднял класс исключения EInvalidCast с сообщением «Недопустимый тип класса»

Вот код:

Интерфейс в отдельном пакете Plugin_interface.bpl :

unit MainIntf;

interface
  Type IMainInft = interface
  ['{FE08C4A2-069C-4B8C-BB1B-445348CAB6A0}']
    function GetForm : TObject;
  end;

implementation

end.

Внедрение интерфейса в Project1.exe:

unit MainImpl;

interface
uses MainIntf;

  Type TMain = class(TInterfacedObject,IInterface,IMainInft)
    function GetForm : TObject;
end;


implementation
uses unit1;

function TMain.GetForm: TObject ;
begin
  result:=Form1; // interafce is implemented on the main form so Form1 is rechable form here
end;


end.

И, наконец, в другом пакете "plugin.bpl" я пытаюсь получить объект из интерфейса:

unit Plugin_main;

interface
uses Mainintf, Vcl.Forms;

type TPlugin = class (Tobject)
  IIMyRefernceToMianIntf: IMainInft;
end;

function RegisterPlugin(AMainIntf: IMainInft): TForm ; export;
procedure UnRegisterPlugin; export;

exports
  RegisterPlugin,
  UnRegisterPlugin;

var
 Plugin_obj:  TPlugin;

implementation
uses vcl.Dialogs,System.Classes ;

function RegisterPlugin(AMainIntf: IMainInft): TForm ;
var
 MyForm : TForm ;
begin
  Plugin_obj:=TPlugin.Create;
  Plugin_obj.IIMyRefernceToMianIntf:=AMainIntf;

  if AMainIntf.GetForm is TForm then
    Showmessage ('Great it is a Tform') // will not happen
  else
    Showmessage ('Sorry  it is not Tform'); // will happen 
  if TComponent (AMainIntf.GetForm).Classname='TForm1' then
    Showmessage ('What ?? It is TForm1 decsendant from TForm  so is it TForm after all ?!');  // will happen 
// result:=  AMainIntf.GetForm as TForm  -- This will rise na exception
  result:= TForm( AMainIntf.GetForm)  ; // this will work

end;

procedure UnRegisterPlugin;
begin
  Plugin_obj.Free;
end;
end.

Почему я не могу использовать ключевые слова «как» и «есть». Подойдет только жесткий кэтсинг, но я ненавижу это делать. на компиляторе XE8 все работало как положено - проблема существует на компиляторе XE 10.2 tokyo


person jackDph    schedule 13.06.2017    source источник
comment
Ваши проекты скомпилированы с включенными пакетами среды выполнения? Этот тип ошибки обычно означает, что один экземпляр библиотек RTL/VCL не используется совместно с исполняемыми файлами, что приводит к разным значениям RTTI для каждого исполняемого файла.   -  person Remy Lebeau    schedule 13.06.2017
comment
Спасибо Реми — вот и все — эта опция была перемещена в XE10.2 и теперь называется Ссылка с пакетами среды выполнения на отдельной странице параметров под названием Пакеты среды выполнения.   -  person jackDph    schedule 13.06.2017
comment
@jackDph: нет XE 10.2. Это Delphi или RAD Studio 10.2, XE не видно. Линия XE остановилась на XE8.   -  person Rudy Velthuis    schedule 13.06.2017
comment
@RemyLebeau, вы действительно должны превратить это в ответ или, лучше, найти дубликат и закрыть его.   -  person Johan    schedule 13.06.2017


Ответы (1)


Ключевое слово «есть» проверяет фактические объекты, чтобы увидеть, что они того типа, который вы запрашиваете. Итак, проверка на это:

if AMainIntf.GetForm is TForm then
Showmessage ('Great it is a Tform') // will not happen

не происходит, потому что GetForm возвращает TObject, а не TForm. Проверка с помощью «есть» также означает, что вы проверяете возможность приведения, то есть возможность использовать ключевое слово «как». Поскольку проверка «есть» не выполняется, эта команда также не выполняется:

result:=  AMainIntf.GetForm as TForm;

Следующим вариантом здесь является жесткое преобразование GetForm так, как вы это делаете:

TForm(AMainIntf.GetForm);

который работает, потому что это приведение не проверяет, относится ли GetForm к типу TForm. Так как вы возвращаете форму в TMain, этот жесткий кастинг для вас беспроигрышный вариант.

Сказав это, однако, почему бы вам не вернуть TForm напрямую, а не TObject? Используете ли вы IMainInft в других классах, которые возвращают другие типы, чем TForm?

person John Kouraklis    schedule 22.06.2017
comment
Оператор as будет работать до тех пор, пока объект слева имеет TForm где-то в своей иерархии классов. Проблема здесь (как заявляет Реми в своем комментарии выше) заключается в том, что BPL не делился данными типа с исполняемым файлом, поэтому имел другой TForm. - person Nat; 22.06.2021