![]() |
Klonen eines Interfaces
Ich habe gerade das Gefühl ein Brett vor dem Kopf zu haben.
Beim Refactoring einer vorhandenen Software baue ich gerade etwas zu einem Interface um. Vorher war das ein einfacher Record und eine Unit mit ein paar Prozeduren und Funktionen. Ich brauche jetzt eine Methode, um die Inhalte einer Instanz auf eine andere zu kopieren. Mein Problem dabei ist, dass ich mich irgendwie im Kreis drehe. Die Instanzen werden auf Basis des Interfaces erzeugt. Die Inhalte sind aber zum Teil erst im InterfacedObject enthalten, bzw. über Properties erreichbar, deren Setter aber dazu führt, dass interne Changed-Kennzeichen gesetzt werden, was ich aber beim Kopieren nicht haben will. Die Sourcen in abgespeckter Version: Das Interface:
Delphi-Quellcode:
Die Klasse:
IMyInt = interface
// Setter procedure SetA(AValue: Boolean); // Getter function GetA: Boolean; function GetB: String; function Clone: IMyInt; function Save: Boolean; // Properties property A: Boolean read GetA write SetA; property B: String read GetB; end;
Delphi-Quellcode:
In der Anwendung selbst, gibt es bereits zwei Instanzen. Es geht also nur darum, die Inhalte von einer Instanz in die Andere zu kopieren, ohne automatische fChanged zu setzen und dabei auch alles zu kopieren. Für Property B gibt es zum Beispiel keinen Setter. Das ganze würde ich gerne über eine Methode innerhalb der Klasse lösen. Da die Instanzen vom Typ IMyInt sind, kann ich nicht auf die Member-Variablen zugreifen. Ich habe gestern noch einiges probiert, hatte aber irgendwann das Gefühl mich im Kreis zu drehen und mir selbst den Blick für die Lösung zu verstellen.
TMyClass = class(TInterfacedObject, IMyInt)
strict private fA: Boolean; fB: String; fChanged: Boolean; private procedure SetA(AValue: Boolean); function GetA: Boolean; function GetB: String; public constructor Create; destructor Destroy(); override; function Clone: IMyInt; function Save: Boolean; property A: Boolean read GetA write SetA; property B: String read GetB; end; .... procedure TMyClass.SetA(AValue: Boolean); begin if fA <> AValue then begin fChanged := True; fA := AValue; end; end; Kann ich jemand mal in die richtige Richtung schubsen? |
AW: Klonen eines Interfaces
Meinst du sowas?
Delphi-Quellcode:
function TMyClass.Clone: IMyInt;
begin Result := TMyClass.Create; TMyClass(Result).fA := Self.fA; end; |
AW: Klonen eines Interfaces
hm, zusätzliche Variable InCloning, also so:
Code:
TMyClass = class(TInterfacedObject, IMyInt)
strict private fA: Boolean; fB: String; fChanged: Boolean; fInCloning: Boolean; private procedure SetA(AValue: Boolean); function GetA: Boolean; function GetB: String; public constructor Create; destructor Destroy(); override; function Clone: IMyInt; function Save: Boolean; property A: Boolean read GetA write SetA; property B: String read GetB; end; .... procedure TMyClass.SetA(AValue: Boolean); begin if fA <> AValue then begin if not fInCloning then fChanged := True; fA := AValue; end; end; function TMyClass.Clone: IMyInt; begin fInCloning := True; try <bisheriger Clone-Code> finally fInCloning := False; end; end; |
AW: Klonen eines Interfaces
Das hier sollte funktionieren:
Delphi-Quellcode:
(sehe dass die Lösung schon vorgeschlagen wurde - einziger Unterschied ist der "hard cast")
function TMyClass.Clone: IMyInt;
var MyClass: TMyClass; begin MyClass := TMyClass.Create; MyClass.fA := Self.fA; MyClass.fB := Self.fB; Result := MyClass end; (siehe ![]() |
AW: Klonen eines Interfaces
Zitat:
|
AW: Klonen eines Interfaces
Zitat:
Ein bekannter und berüchtigter Referenzzählungs-Bug entsteht, wenn man an einen Parameter, der einen Interfacetyp hat, eine frisch erzeugte Instanz übergibt:
Delphi-Quellcode:
procedure Machwas(MyInt: IMyInt);
... ... ... MachWas(TMyClass.Create); // bad things will happen |
AW: Klonen eines Interfaces
Vielen Dank exon und perpeto1234.
Ich kann jetzt nicht sagen, welcher Vorschlag bei mir den Knoten hat platzen lassen, aber ich habe einen neuen Ansatz gefunden. Es wird jetzt nicht über eine Clone-Funktion gemacht, die von der Quelle kommt, sondern eine Prozedure "CloneFrom" die als Parameter die Quelle bekommt. Dann kann ich auf alle vorhandenen Member-Variablen zugreifen und alles ohne Setter setzen. @mjustin: Deinen Ansatz werde ich mir merken. Der passt hier aber nicht ganz, da Quelle und Ziel als Instanzen bereits existieren. |
AW: Klonen eines Interfaces
Zitat:
Delphi-Quellcode:
procedure TMyClass.CopyFrom(AOther: TMyClass);
begin Self.fA := AOther.fA; Self.fB := AOther.fB; end; |
AW: Klonen eines Interfaces
Im Prinzip ist das genau der Ansatz, den ich jetzt genommen habe. Das geht auch mit dem Interface als Parameter, wenn die Properties auch im Interface deklariert sind.
|
AW: Klonen eines Interfaces
PS: Wenn es dir nur darum geht, dass es wie ein Interface/Objekt aussieht, also die Methoden und die Daten zusammen und die Funktionen in der "Klasse" drin,
dann kann man die einzelnen Funktionen auch als Methoden in den Record verschieben, statt einem Parameter auf Self zugreifen und fertig. Bezüglich des Kopierens kannst dann diesen Record weiterhin genauso behandeln, wie bisher. Ansonsten nimmt man im Allgemeinen eine Funktion, welche sich ![]() ![]() Da drin mußt du dann die Property/Felder des einen Objekts in das andere Kopieren. Beim normalen Assign mit allgemeinem Typen wird intern nochmals geprüft, ob der Typ passt, aber hier kannst du einfach dem Parameter den richtigen Typen geben und schon kann nur der richtige Typ reingegeben werden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:14 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 by Thomas Breitkreuz