AGB  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Mischen von Interface- und Klassenreferenzen

Mischen von Interface- und Klassenreferenzen

Ein Thema von mjustin · begonnen am 20. Mär 2018 · letzter Beitrag vom 21. Mär 2018
Antwort Antwort
mjustin

Registriert seit: 14. Apr 2008
2.511 Beiträge
 
Delphi 2009 Professional
 
#1

Mischen von Interface- und Klassenreferenzen

  Alt 20. Mär 2018, 13:45
Delphi-Version: 5
Hallo,

im neuen Blogartikel "Don't mix objects and interfaces" erläutert Dalija Prasnikar die Probleme die entstehen wenn Objekte und Interface vermischt werden.

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:
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;
Laut Blogartikel ist allerdings das

TmpFoo := TmpFoo.Create();

ein "huge no-no". Ist das Codebeispiel dennoch eine saubere Verwendung von Interfaces?
Michael Justin
habarisoft.com
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.711 Beiträge
 
FreePascal / Lazarus
 
#2

AW: Mischen von Interface- und Klassenreferenzen

  Alt 20. Mär 2018, 13:57
In diesem speziellen Fall sollte es keine Probleme verursachen.

Gefährlich ist aber z.B. sowas:
Delphi-Quellcode:
procedure DoSomethingWithFoo(Foo: IFoo);
begin
end;

function CreateFoo: IFoo;
var
  TmpFoo: TFoo;
begin
  TmpFoo := TmpFoo.Create();
  TempFoo.X := 1;

  DoSomethingWithFoo(TmpFoo);

  Result := TmpFoo;
end;
In dem Fall würde es crashen, weil intern grob folgendes passiert:
Delphi-Quellcode:
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;
Es muss natürlich nicht genau an der Stelle crashen, sondern kann auch irgendwann später crashen.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
5.523 Beiträge
 
Delphi 10.2 Tokyo Architect
 
#3

AW: Mischen von Interface- und Klassenreferenzen

  Alt 20. Mär 2018, 14:18
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 TInterfacedObject . 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.NewInstance der RefCount künstlich auf 1 gesetzt:
Delphi-Quellcode:
// 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;
Dies wird dann im AfterConstruction wieder zurückgenommen:
Delphi-Quellcode:
procedure TInterfacedObject.AfterConstruction;
begin
// Release the constructor's implicit refcount
  AtomicDecrement(FRefCount);
end;
Die darauf folgende Zuweisung auf eine Interface-Referenz sorgt dann wieder für das korrekte RefCounting.

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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
1.186 Beiträge
 
Delphi 2007 Professional
 
#4

AW: Mischen von Interface- und Klassenreferenzen

  Alt 21. Mär 2018, 14:04
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;
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:04 Uhr.
Powered by vBulletin® Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2018 by Daniel R. Wolf