Delphi-Version: 2009
Verständnisfrage: Interface und dazugehöriges Objekt
Bin gerade über alten Code gestoßen und bin mir unsicher, ob das so sein darf:
Delphi-Quellcode:
In dem vereinfachten und gekürzten Beispiel muss noch die Variable Example von Typ IContainer sein, so wie im Kommentar angedeutet, oder etwas nicht? :?:
class function TContainer.CreateContainer(...) : IContainer;
var BlaType : IBlaType; Example : TContainer; //IContainer; begin Result := nil; Example := TContainer.Create(...); if Assigned(Example) and FindBlaType(...) then begin Example.SetIrgendwas(BlaType); Result := Example; end; end; Hab ich hier den Fall vorliegen, vor dem immer gewarnt wird? "Du sollst nicht Interface- und Objekt-Referenzen mischen!" |
AW: Verständnisfrage: Interface und dazugehöriges Objekt
Solltest du wahrlich machen. Sonst bekommst ein Problem mit der autom. Referenzzählung!
Zitat:
Wobei ich den Code eh nicht ganz verstehe, wenn ich ehrlich bin... Wieso sollte Assigned nach dem Create jemals False liefern? Create ist schon ein Konstruktor? Diese Methode würde in der aktuellen Version eh niemals nil liefern. In so fern Create eine Exception wirft, wird diese ja nicht abgefangen -- außer du hast natürlich diesen Code entfernt ;) |
AW: Verständnisfrage: Interface und dazugehöriges Objekt
In dem gezeigten Code ist es so, daß hier nicht beide Referenzen "gleichzeitig" verwendet werden.
(oftmals macht man sowas, wenn auf eine Funktion des Objekts zugreifen will, welche man "vergessen" hat ins Interface aufzunehmen) Objekt vor Interface funktioniert oftmals noch.
Delphi-Quellcode:
=> Selbst wenn hier Example ein IContainer wäre, würde es kurz vor der Zuweisung noch als Objekt behandelt.
Example := TContainer.Create(...);
Es kommt jetzt allerdings noch drauf an, was
Delphi-Quellcode:
und
FindBlaType(...)
Delphi-Quellcode:
macht und ob darin eine Interfacereferenz dieses Objekts erzeugt/verwendet wird, denn dann hat man mit diesem Vorgehen ein Problem, da man dann Interface- und Objektreferenz gleichzeitig verwendet.
SetIrgendwas
Objekt nach Interface ist standardmäig nicht möglich, da man hierfür, bei Freigabe der letzen Interfacereferenz, die Freigabeautomatik des Interfaces deaktivieren müßte. Bzw. man muß an den Stellen, wo man es in als Objekt benötigt, sicherstellen, daß über diese Dauer immer mindestens eine Interfacereferenz existiert. Außerdem gibt es hier ein Speicherleck, wenn das IF ein False liefert, bzw. wenn es eine Exception gibt ... also wenn der Programmablauf nicht beim
Delphi-Quellcode:
vorbei kommt, da sich dann niemand dafür verantwortlich hält, dieses Objekt wieder freizugeben.
Result :=
|
AW: Verständnisfrage: Interface und dazugehöriges Objekt
So wäre es richtig:
Delphi-Quellcode:
class function TContainer.CreateContainer(...) : IContainer;
var BlaType : IBlaType; begin Result := TContainer.Create(...); if FindBlaType(...) then begin Example.SetIrgendwas(BlaType); end else Result := nil; end; |
AW: Verständnisfrage: Interface und dazugehöriges Objekt
Also so sieht es eigentlich aus, musste aber Firmenspezifische Abkürzungen von ein paar Bezeichnern entfernen.
Die Kommentare sind von mir für euch zur Erklärung!
Delphi-Quellcode:
Zur meiner Verteidigung muss ich sagen, dass das nicht von mir, sondern von meinen Vorgänger stammt.
class function TNotifyEventContainer.CreateContainer(ANotification : HNotification; AExtMedium : IAExtMedium) : IEventContainer;
var EventType : IEventType; Event : TNotifyEventContainer; //IEventContainer; begin Result := nil; if Assigned(AExtMedium) then begin //in diesem Create steckt ein "leeres" Try-Except mit nur OutputDebugString um den Konstruktur-Code Event := TNotifyEventContainer.Create(ANotification, AExtMedium.GetAliasName, AExtMedium.GetGuid); //FindEventType ist eine flache Funktion in der Unit. //GetEventTypes liefert eine IInterfaceList. //EventType ist ein out-Parameter, die Funktion sucht in der Liste anhand //von GetEventTypeID das betreffende IEventType in der IInterfaceList und gibt es zurück if Assigned(Event) and FindEventType(AExtMedium.GetEventTypes, Event.GetEventTypeID, EventType) then begin //setzt nur EventType als Field-Variable von TNotifyEventContainer Event.SetEventType(EventType); end; Result := Event; end; end; Ich wäre hierrüber auch nie gestoßen, hätte ich nicht manchmal merkwürdige Effekte/Fehlermeldungen, seitdem ich FastMM4 installiert habe. Der alte Speichermanager hatte wahrscheinlich beide Augen zugedrückt. |
AW: Verständnisfrage: Interface und dazugehöriges Objekt
Zitat:
Zitat:
Es kann schon passieren, dass beim Erstellen der Klasse irgendwas schiefgeht. Darum hat mein Vorgänger um den Code im Create ein leeres try-except gestrickt. Wenn es nun dadrin zur einer Exception kommt, dann existiert Example/Event nicht und jeder Zugriff drauf würde doch mit einer AV enden, oder? |
AW: Verständnisfrage: Interface und dazugehöriges Objekt
Zitat:
Wobei ich dabei auch immer irgendwie Bauchschmerzen habe.
Delphi-Quellcode:
TMyClass = class;
IMyInterface function GetObject : TMyClass; end; TMyClass = class(TInterfacedObject, IMyInterface) function GetObject : TMyClass; end ... function TMyClass.GetObject : TMyClass; begin Result := self; end; |
AW: Verständnisfrage: Interface und dazugehöriges Objekt
:gelöscht:
|
AW: Verständnisfrage: Interface und dazugehöriges Objekt
Wenn etwas im Constructor schief geht, dann maximal eine Exception.
Also entweder wird der Constructor ausgeführt (keine Exception) und die Variable wird zugewiesen, oder es knallt mit einer Exception raus, der variable wird nix zugewiesen, aber auch der nachfolgende Code wird nicht mehr ausgeführt. Wenn das Programm zum IF kommt, sollte es immer etwas drinsteht, also niemals nil. (es sei denn jemand überschreibt TObject.NewInstance und gibt dort bösartiger Weise NIL zurück, aber das ist soein Fall, den braucht man nicht beachten, denn wer sowas tut, der soll sich nicht wundern, wenn es dann wo anders knallt)
Delphi-Quellcode:
type
TMyObject = class constructor Create; end; constructor TMyObject.Create; begin Abort; // raise Exception.Create('peng'); end; var O: TObject; begin O := TMyObject.Create; if Assigned(O) then ShowMessage('OK') else ShowMessage('nil'); // das sieht man niemals Zitat:
Nur sieht man dort dieses "Interface" nicht direkt, da es kein echtes Interface ist, sondern eine statische GUID, welche im AS-Operator wie ein virtuelles Interface behandelt wird.
Delphi-Quellcode:
var
i: IMyInterface; o: TMyObject; o := i as TMyObject;
Delphi-Quellcode:
Aber wie gesagt, man muß wärend man auf dieses Objekt zugreift unbedingt verhindern, daß der Referenzzähler auf 0 geht, jedenfalls bei Interfaces welche sich über die Referenzzählung verwaltet werden.
type
IMyInterface = interface ['{C6936E1B-F0FE-42A0-A00E-39E90A66A9F0}'] procedure Test; end; TMyObject = class(TInterfacedObject, IMyInterface) FText: string; constructor Create; procedure Test; end; procedure TMyObject.Test; begin ShowMessage(FText); end; constructor TMyObject.Create; begin inherited; FText := 'Hallo Welt.'; end; procedure TForm10.Button3Click(Sender: TObject); var I: IMyInterface; O: TMyObject; begin I := TMyObject.Create; O := I as TMyObject; O.Test; I := nil; // letzte und einzige Interfacereferenz vernichten O.Test; end; Bei Onterfaces wo die Freigabe anders gesteuert wird, muß mn eben aufpassen, daß dieses ebenfalls nicht freigegeben wird. PS: TComponent enthalten Interfaces, welche sich nicht selber freigeben. Die Freigabe geschieht dort ausschließtlich über das Objekt (Free) und dem Free ist es egal, ob es irgendwo noch Referenzen auf dieses Interfaces/Objekt gibt. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:29 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