あなたの問題を解決するための1つのアプローチは、コードを変更して、インタフェース参照によってオブジェクトを参照することだけです。言い換えれば、
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;
このクラスからクラスを派生させることができます。
このアプローチには非常に大きな警告が1つあります。 TInterfacedObjectWithoutLifetimeManagement
から派生したクラスによって実装されているインタフェースを変数(ローカル、グローバル、クラスメンバ)で保持しているとします。すべてのそのようなインタフェース変数は、実装オブジェクトに対して Free
を呼び出す前に確定する必要があります。
この規則に従わないと、それらのインタフェース変数が有効範囲外になると、コンパイラは引き続き _Release
を呼び出すコードを発行し、オブジェクトのメソッドを呼び出すとエラーになります破壊されました。これは特に重要なクライアントのマシンでコードが実行されるまでランタイムエラーが発生しないため、特に厄介なタイプのエラーです。換言すれば、そのようなエラーは断続的な性質を有する可能性がある。