Один из подходов к решению вашей проблемы - изменить код так, чтобы вы когда-либо обращались к объекту только через ссылку на интерфейс. Другими словами вместо
var
obj: TMyObject;
...
obj := TMyObject.Create;
try
obj.DoStuff;
//etc. etc.
finally
obj.Free;
end;
Вы пишете
var
obj: IMyObject;//NOTE: interface variable
...
obj := TMyObject.Create;
obj.DoStuff;
//etc. etc.
obj := nil;//or let it go out of scope and release that way
Это может быть неудобно, поэтому вместо этого может быть удобнее отключить автоматическое управление временем жизни. Вы должны сделать это для вашего объекта реализации:
type
TInterfacedObjectWithoutLifetimeManagement = class(TObject, IInterface)
private
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
function TInterfacedObjectWithoutLifetimeManagement.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then
Result := 0
else
Result := E_NOINTERFACE;
end;
function TInterfacedObjectWithoutLifetimeManagement._AddRef: Integer;
begin
Result := -1;
end;
function TInterfacedObjectWithoutLifetimeManagement._Release: Integer;
begin
Result := -1;
end;
Затем вы можете получить свои классы из этого класса.
В этом подходе есть одно очень серьезное замечание. Предположим, что вы храните в переменных (локальных, глобальных, член класса) все интерфейсы, которые реализуются классом, производным от TInterfacedObjectWithoutLifetimeManagement
. Все такие переменные интерфейса должны быть завершены за до вызова Free
для реализующего объекта.
Если вы не будете следовать этому правилу, вы обнаружите, что когда эти переменные интерфейса выходят за пределы области видимости, компилятор по-прежнему генерирует код для вызова _Release
, и вызывать метод объекта после его уничтожения - ошибка Это особенно неприятный тип ошибки, потому что он обычно не проявляется с ошибкой во время выполнения, пока ваш код не будет запущен на компьютере вашего самого важного клиента! Другими словами, такие ошибки могут иметь прерывистый характер.