AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Interfaces UND Objektreferenzen mischen

Ein Thema von himitsu · begonnen am 6. Nov 2011 · letzter Beitrag vom 6. Nov 2011
Antwort Antwort
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#1

Interfaces UND Objektreferenzen mischen

  Alt 6. Nov 2011, 09:25
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 http://www.delphipraxis.net/164271-d...ml#post1134663 nicht möglich ist.
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:
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;
Es wird also nun jeweils erst bei dem wirklich freigegeben, welches zurletz noch vorhanden ist.
Womit dann z.B. Sowas gemacht werden könnte:
Delphi-Quellcode:
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;
Das Ganze ist also quasi eine Mischung aus einem Interface-Pattern und einem Singleinstanz-Pattern.

Wäre schön, wenn da nochmal wer reinsehn könnte ... nicht daß ich da noch irgendwas übersehn hab.

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.
Angehängte Dateien
Dateityp: pas VTAControls.pas (7,1 KB, 6x aufgerufen)
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.027 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#2

AW: Interfaces UND Objektreferenzen mischen

  Alt 6. Nov 2011, 12:40
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 CreateIntf<T> 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.

Aber nebenbei bemerkt, frag ich mich, warum du solche Verrenkungen für was total Simples machst...

Delphi-Quellcode:
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;
getestet mit:

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;
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie ( 6. Nov 2011 um 12:49 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#3

AW: Interfaces UND Objektreferenzen mischen

  Alt 6. Nov 2011, 13:07
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.

PS: Genau so hatte ich auch angefangen.
$2B or not $2B

Geändert von himitsu ( 6. Nov 2011 um 14:49 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.027 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#4

AW: Interfaces UND Objektreferenzen mischen

  Alt 6. Nov 2011, 14:43
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.
Dann schreibt man dort inherited rein? Und NewInstance und FreeInstance überschreibt man mal nicht so aus "Versehen".
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie ( 6. Nov 2011 um 14:50 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#5

AW: Interfaces UND Objektreferenzen mischen

  Alt 6. Nov 2011, 15:11
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.
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.027 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#6

AW: Interfaces UND Objektreferenzen mischen

  Alt 6. Nov 2011, 16:04
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.
Crap Hab garnicht mehr dran gedacht, dass Free stumpf Destroy aufruft
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:41 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz