Быстрый ответ
Ваш интерфейс должен иметь 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.