![]() |
Delphi-Version: 5
Mischen von Interface- und Klassenreferenzen
Hallo,
im neuen Blogartikel " ![]() Ihre Codebeispiel sind überraschend, denn wie hier in der DP gelegentlich geschrieben wurde kann in Factorymethoden eine interne Instanz der Klasse erzeugt werden und am Ende eine Interfacereferenz zurückgegeben:
Delphi-Quellcode:
Laut Blogartikel ist allerdings das
function CreateFoo: IFoo;
var TmpFoo: TFoo; begin // Instanz der Klasse TmpFoo erzeugen, die von TInterfacedObject abgeleitet ist und IFoo implementiert TmpFoo := TmpFoo.Create(); // diverse Properties setzen die nicht Teil des IFoo Interface sind TempFoo.X := 1; // ... // Interface zurückgeben Result := TmpFoo; end; TmpFoo := TmpFoo.Create(); ein "huge no-no". Ist das Codebeispiel dennoch eine saubere Verwendung von Interfaces? |
AW: Mischen von Interface- und Klassenreferenzen
In diesem speziellen Fall sollte es keine Probleme verursachen.
Gefährlich ist aber z.B. sowas:
Delphi-Quellcode:
In dem Fall würde es crashen, weil intern grob folgendes passiert:
procedure DoSomethingWithFoo(Foo: IFoo);
begin end; function CreateFoo: IFoo; var TmpFoo: TFoo; begin TmpFoo := TmpFoo.Create(); TempFoo.X := 1; DoSomethingWithFoo(TmpFoo); Result := TmpFoo; end;
Delphi-Quellcode:
Es muss natürlich nicht genau an der Stelle crashen, sondern kann auch irgendwann später crashen.
procedure DoSomethingWithFoo(Foo: IFoo);
begin end; function CreateFoo: IFoo; var TmpFoo: TFoo; TmpInterface: IFoo; begin TmpFoo := TmpFoo.Create(); // RefCount = 0 TempFoo.X := 1; TmpInterface := TmpFoo; // inc(RefCount) (= 1) DoSomethingWithFoo(TmpInterface); TmpInterface := nil; // dec(RefCount) (= 0) -> TmpFoo.Free; Result := TmpFoo; // inc(RefCount)... crash, weil Objekt schon freigegeben ist end; |
AW: Mischen von Interface- und Klassenreferenzen
Die Äußerungen beziehen sich auch nur auf den Fall, wo auch ein Reference-Counting stattfindet - genauer dieses zum Destroy der Instanz führt. Dies gilt z.B. bei allen Abkömmlingen von
Delphi-Quellcode:
. Damit im Create einer solchen Klasse das RefCounting keinen Ärger macht (dort gibt es nämlich noch keine Interface-Referenz, die das Objekt am Leben halten könnte), wird im
TInterfacedObject
Delphi-Quellcode:
der RefCount künstlich auf 1 gesetzt:
TInterfacedObject.NewInstance
Delphi-Quellcode:
Dies wird dann im AfterConstruction wieder zurückgenommen:
// Set an implicit refcount so that refcounting during construction won't destroy the object.
class function TInterfacedObject.NewInstance: TObject; begin Result := inherited NewInstance; TInterfacedObject(Result).FRefCount := 1; end;
Delphi-Quellcode:
Die darauf folgende Zuweisung auf eine Interface-Referenz sorgt dann wieder für das korrekte RefCounting.
procedure TInterfacedObject.AfterConstruction;
begin // Release the constructor's implicit refcount AtomicDecrement(FRefCount); end; Beim Destroy gibt es aber eine sehr ähnliche Problematik, wenn z.B. im Destroy irgendwelche RefCounting relevante Befehle ausgeführt werden. Dort wählt man aber mittlerweile (seit XE7 - in älteren Versionen crasht das noch) einen anderen Weg über ein Flag namens objDestroyingFlag. Wie immer muss man halt genau wissen was man tut. |
AW: Mischen von Interface- und Klassenreferenzen
Namenloser hat das richtig dargestellt.
Die Factorymethode hat nur eine Aufgabe, das Interface-Objekt zu erstellen. Das fertige Objekt als Interface zu verwenden, gehört nicht zu dieser Aufgabe. Wenn das erfoderlich ist, sollte man in zwei Methoden trennen.
Delphi-Quellcode:
function CreateFoo: IFoo;
var TmpFoo: TFoo; begin // Instanz der Klasse TmpFoo erzeugen, die von TInterfacedObject abgeleitet ist und IFoo implementiert TmpFoo := TmpFoo.Create(); // diverse Properties setzen die nicht Teil des IFoo Interface sind TempFoo.X := 1; // ... // Interface zurückgeben Result := TmpFoo; end; function CreateAndInitFoo: IFoo; begin Result := CreateFoo; DoSomethingWithFoo(Result); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:01 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