Привести TInterfacedObject к интерфейсу - PullRequest
5 голосов
/ 27 марта 2011

Согласно документации Delphi , я могу привести TInterfacedObject к интерфейсу, используя оператор as.

Но это не работает для меня. Приведение дает ошибку компиляции: «Оператор не применим к этому типу операнда».

Я использую Delphi 2007.

Вот некоторый код (консольное приложение). Строка, содержащая ошибку, помечена.

program Project6;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  IMyInterface = interface
    procedure Foo;
  end;

  TMyInterfacedObject = class(TInterfacedObject, IMyInterface)
  public
    procedure Foo;
  end;

procedure TMyInterfacedObject.Foo;
begin
  ;
end;

var
  o: TInterfacedObject;
  i: IMyInterface;
begin
  try
    o := TMyInterfacedObject.Create;
    i := o as IMyInterface;  // <--- [DCC Error] Project6.dpr(30): E2015 Operator not applicable to this operand type
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.

Ответы [ 3 ]

14 голосов
/ 27 марта 2011

Быстрый ответ

Ваш интерфейс должен иметь GUID для работы оператора as.Перейти к первой строке после IMyInterface = interface, перед любым определением метода и нажать Ctrl + G , чтобы сгенерировать новый GUID.

Более длинный комментарий

Оператор as для интерфейсов требует GUID, потому что он вызывает IUnknown.QueryInterface, а это, в свою очередь, требует GUID.Это нормально, если вы столкнетесь с этой проблемой при приведении ИНТЕРФЕЙСА к другому типу ИНТЕРФЕЙСА.

Вы не должны вначале приводить TInterfacedObject к интерфейсу, потому что это означает, что вы 'удерживая как ссылку на реализующий объект (TInterfacedObject), так и ссылку на реализованный интерфейс (IMyInterface).Это проблематично, потому что вы смешиваете две концепции управления жизненным циклом: TObject живут, пока что-то не вызовет .Free;Вы уверены, что ничто не вызывает .Free на ваших объектах без вашего ведома.Но интерфейсы подсчитываются по ссылке: когда вы присваиваете свой интерфейс переменной, счетчик ссылок увеличивается, когда этот экземпляр выходит за рамки (или ему назначается что-то еще), счетчик ссылок уменьшается.Когда счетчик ссылок достигает нуля, объект удаляется (.Free)!

Вот некоторый невинно выглядящий код, который быстро доставит массу неприятностей:

procedure DoSomething(If: IMyInterface);
begin
end;

procedure Test;
var O: TMyObjectImplementingTheInterface;
begin
  O := TMyObjectImplementingTheInterface.Create;
  DoSomething(O); // Works, becuase TMyObject[...] is implementing the given interface
  O.Free; // Will likely AV because O has been disposed of when returning from `DoSomething`!
end;

Исправление очень простое: измените тип O с TMyObject[...] на IMyInterface, например:

procedure DoSomething(If: IMyInterface);
begin
end;

procedure Test;
var O: IMyInterface;
begin
  O := TMyObjectImplementingTheInterface.Create;
  DoSomething(O); // Works, becuase TMyObject[...] is implementing the given interface
end; // `O` gets freed here, no need to do it manually, because `O` runs out of scope, decreases the ref count and hits zero.
2 голосов
/ 27 марта 2011

Если вы хотите использовать оператор «Как» или «Поддерживает», вам необходимо добавить Guid в интерфейс, например:

type   
  IMyInterface = interface
    ['{00000115-0000-0000-C000-000000000049}']
    procedure Foo;   
  end; 

См. Документация

0 голосов
/ 27 марта 2011

Приведение будет автоматическим, если вы определите объект o как правильный тип. В противном случае вы всегда можете использовать supports() и / или позвонить QueryInterface самостоятельно.

var
  o: TMyInterfacedObject;
  i: IMyInterface;
begin
  try
    o := TMyInterfacedObject.Create;
    i := o;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.
...