Hallo mirage228,
wenn ich Deine Ausführungen richtig verstanden habe, liegt die Ursache des Problems in der heterogenen Verwendung von Klassen(-Objekten) und (Objekt-)Interfaces.
Bedingt durch das in Delphi verwendete Interface-Konzept wird bei der Arbeit mit Interfaces eine implizite Referenzzählung vorgenommen.
Der folgende Code
Delphi-Quellcode:
var
myObject: IMyInterface
begin
myObject:= GetAnObject;
myObject.AMethod;
myObject:= GetAnotherObject;
myObject.AnotherMethod;
end;
wird deshalb vom Compiler um Code ergänzt, den man etwa so schreiben könnte
Delphi-Quellcode:
begin
myObject:= GetAnObject;
myObject._AddRef;
myObject.AMethod;
myObject._Release;
myObject:= GetAnotherObject
myObject._AddRef;
myObject.AnotherObject;
myObject._Release;
end;
Tatsächlich variiert der Aufruf von
_Release ein wenig, so dass in diesem Beispiel die Methode erst nach dem Aufruf von
GetAnotherObject aufgerufen wird, darüber hinaus sollte man sich die Referenzzählung von
try..finally-Blöcken umschlossen vorstellen, der Einfachheit halber habe ich das aber vernachlässigt.
Betrachtet man nun die Implementierung von
_Release in dem von Dir verwendeten Vorfahren
TInterfacedObject:
Delphi-Quellcode:
function TInterfacedObject._Release: Integer;
begin
Result := InterlockedDecrement(FRefCount);
if Result = 0 then
Destroy;
end;
Erkennt man, dass Objekte dieses Typs freigegeben werden, sobald der Referenzzähler null erreicht hat. Weil ein solches Objekt nach dem Verlassen des Konstruktors mit null belegt ist führt dieser Code
Delphi-Quellcode:
var
myClassicalObject: TInterfacedObject;
myInterfacedObject: IInterface;
begin
myClassicalObject:= TInterfacedObject.Create;
myInterfacedObject:= myClassicalObject; // implicit call of _AddRef
myInterfacedObject:= nil; // implicit call of _Release -> Free;
// !myClassicalObject contains an invalid reference, now
Showmessage(IntToStr(myClassicalObject.RefCount));
end;
zu Problemen (dass der Code fehlerfrei funktionieren kann, liegt an der Speicherverwaltung von Delphi, führt aber spätestens bei mehreren parallelen Verarbeitungssträngen zu Problemen).
Wenn Du Dich mit diesem Phänomen eingehender beschäftigen möchtest, empfehle ich Dir, eine Testklasse zu implementieren, die die Methoden
_AddRef und
_Release sowie den Aufruf des Destruktors protokolliert, bzw den Code im integrierten Debugger mit Debug-DCUs und einem Nachfahren von
TInterfacedObject mit Breakpoints in den entsprechenden Zeilen der
Unit System zu analysieren.
Lösen lassen sollte sich das Problem relativ einfach, indem Du entweder ausschließlich "klassische Objekte" oder Interfaces verwendest. Listen für den letzteren Fall lassen sich dann zB mithilfe von
TInterfaceList realisieren...