![]() |
Interfaces UND Objektreferenzen mischen
Liste der Anhänge anzeigen (Anzahl: 1)
Im Prinzip benötige ich sowas für eine Art Framework, wo man eigene Objekte, eigene Interfaces und fremde Interfaces (gekpselt in eigenen Objekten) paralell nutzen kann.
Also wo ein objekt gleichzeitig als Objektreferenz existiert und als Interface. Leider ging es nicht "einfach", da ![]() Und leider bekommt man im constructor nicht mit, ob das erzeugte Objekt, danach als Objekt oder als Interface genutzt wird. (das zusätzliche CreateIntf erspart)
Delphi-Quellcode:
Es wird also nun jeweils erst bei dem wirklich freigegeben, welches zurletz noch vorhanden ist.
type
_RefObject = class abstract(TObject) private FRefCount: Integer; FVCLFreed: Boolean; FNoDestroy: Integer; class function _NewInstance: TObject; virtual; abstract; procedure _FreeInstance; virtual; abstract; procedure _AfterConstruction; virtual; abstract; procedure _BeforeDestruction; virtual; abstract; destructor _Destroy; virtual; abstract; public class function NewInstance: TObject; override; procedure FreeInstance; override; procedure AfterConstruction; override; procedure BeforeDestruction; override; destructor Destroy; override; end; TRefObject = class(_RefObject, IInterface) class function _NewInstance: TObject; override; procedure _FreeInstance; override; procedure _AfterConstruction; override; procedure _BeforeDestruction; override; destructor _Destroy; override; public class function NewInstance: TObject; reintroduce; virtual; procedure FreeInstance; reintroduce; virtual; procedure AfterConstruction; reintroduce; virtual; procedure BeforeDestruction; reintroduce; virtual; constructor Create; overload; virtual; constructor CreateIntf; overload; class function CreateIntf<I: IInterface>: I; overload; destructor Destroy; reintroduce; virtual; { IInterface } function QueryInterface(const IID: TGUID; out Obj): HRESULT; virtual; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end; Womit dann z.B. Sowas gemacht werden könnte:
Delphi-Quellcode:
Das Ganze ist also quasi eine Mischung aus einem Interface-Pattern und einem Singleinstanz-Pattern.
var
i: IInterface; o: TRefObject; begin o := TRefObject.Create; o.Free; i := TRefObject.CreateInf; i := nil; o := TRefObject.Create; i := o as IInterface; i := nil; o.Free; o := TRefObject.Create; i := o as IInterface; o.Free; i := nil; TRefObject.Create.Free; Wäre schön, wenn da nochmal wer reinsehn könnte ... nicht daß ich da noch irgendwas übersehn hab. :shock: Wenn jemand an der Referenzzählung (_AddRef und _Release) rumspielt oder wenn wer Free/Destroy doppelt aufruft, dann knallt es natürlich irgendwo, aber sowas passiert ja auch bei den normalten Objekten und Interfacen, weswegen ich da keinen Anlaß sah, Dieses (zumindestens das Free/Destroy) entsprechend zu behandeln ... zu oft _Release wird aber erkannt. |
AW: Interfaces UND Objektreferenzen mischen
Die Unterscheidung zwischen Create und CreateIntf ist etwas unglücklich gewählt, hier verhält sich nämlich das direkte zuweisen auf ein Interface mit Create nicht so, wie man es gewohnt ist. Daher lieber die neue Funktionalität explizit benamen.
Die Methode
Delphi-Quellcode:
ist so nicht korrekt und bringt einen E2010: Incompatible types, wenn man irgendwas anders als IInterface als T angibt. Dafür müsstest du Supports oder GetInterface benutzen.
CreateIntf<T>
Aber nebenbei bemerkt, frag ich mich, warum du solche Verrenkungen für was total Simples machst...
Delphi-Quellcode:
getestet mit:
type
TRefObject = class(TObject, IInterface) private FKeepAlive: Boolean; FRefCount: Integer; protected function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; public constructor Create(KeepAlive: Boolean = False); procedure FreeInstance; override; procedure AfterConstruction; override; class function NewInstance: TObject; override; property RefCount: Integer read FRefCount; end; { TRefObject } procedure TRefObject.AfterConstruction; begin InterlockedDecrement(FRefCount); end; constructor TRefObject.Create(KeepAlive: Boolean); begin FKeepAlive := KeepAlive; end; procedure TRefObject.FreeInstance; begin if (FRefCount = 0) or not FKeepAlive then inherited; FKeepAlive := False; end; class function TRefObject.NewInstance: TObject; begin Result := inherited NewInstance; TRefObject(Result).FRefCount := 1; end; function TRefObject.QueryInterface(const IID: TGUID; out Obj): HResult; begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end; function TRefObject._AddRef: Integer; begin Result := InterlockedIncrement(FRefCount); end; function TRefObject._Release: Integer; begin Result := InterlockedDecrement(FRefCount); if (Result = 0) and not FKeepAlive then Destroy; end;
Delphi-Quellcode:
var
i: IInterface; o: TRefObject; begin o := TRefObject.Create; o.Free; i := TRefObject.Create; i := nil; o := TRefObject.Create(True); i := o; i := nil; o.Free; o := TRefObject.Create(True); i := o; o.Free; i := nil; TRefObject.Create.Free; i := TRefObject.Create; end; |
AW: Interfaces UND Objektreferenzen mischen
Jetzt leite mal von deiner Klasse ab und überschreib z.B. den Destructor,
Das kommt ja häufig vor, daß man sich einen eigenen Destructor und Constructor erstellt und darin irgendwas erzeugt/freigibt. Du mußt in allen Nachfahren höllisch aufpassen, da die überschriebenen Methoden immer Vorrang haben ... darum auch die Verrenkungen. :angle: PS: Genau so hatte ich auch angefangen. :lol: |
AW: Interfaces UND Objektreferenzen mischen
Zitat:
|
AW: Interfaces UND Objektreferenzen mischen
Ein Inherited alleine hilft nicht, denn der Destructor darf nicht ausgeführt werden, wenn das Objekt eigentlich noch nicht weg darf, weil noch Interfacereferenzen existieren, obwohl Free aufgerufen wurde.
Du müßtest also in allen Nachfahren und bei allen Destructoren, sowie den eventuellen FreeInstance und BeforeDestruction neben dem inherited auch die IF-Abfrage mit reinmachen, welche die Freigabe verhindern. |
AW: Interfaces UND Objektreferenzen mischen
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:47 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz