Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi privaten Record über Getter heraus geben (https://www.delphipraxis.net/189844-privaten-record-ueber-getter-heraus-geben.html)

stahli 28. Jul 2016 22:36

Delphi-Version: XE3

privaten Record über Getter heraus geben
 
Ich hatte eigentlich gerade ein komplexes Problem beschrieben, konnte das aber jetzt kürzen.
(Testprojekt und Video von der ursprünglichen Frage könnte ich bei Interesse nachliefern)

Also im Kern ergibt sich folgendes:

Ich habe einen Record
Delphi-Quellcode:
  PGuid = ^TGuid;
  TGuid = record
  private
    fTS1: TDateTime;
    fTS2: TDateTime;
    fC: LongWord;
    ....
  public
    ....
    property AsString: String read get_AsString write set_AsString;
und Interfaces bzw. Klassen, die diesen als Eigenschaft benutzen:
Delphi-Quellcode:
  IGuidObj = interface
    ['{4E5492DE-D248-40C8-8AED-EF9819C32FD6}']
    function _get_Guid: TGuid;
    procedure _set_Guid(const aGuid: TGuid);
    property Guid: TGuid read _get_Guid write _set_Guid;
  end;

  TGuidObj = class(TInterfacedObject, IGuidObj)
  protected
    fGuid: TGuid;
    function _get_Guid: TGuid;
    procedure _set_Guid(const aGuid: TGuid);
  public
    constructor Create; overload; virtual;
    constructor Create(aGuid: TGuid); reintroduce; overload; virtual;
    destructor Destroy; override;
    property Guid: TGuid read _get_Guid write _set_Guid;
  end;

Das Problem ist, dass der Getter jetzt eine KOPIE des Records heraus gibt und ich so nicht direkt in das private Feld schreiben kann.
Delphi-Quellcode:
function TGuidObj._get_Guid: TGuid;
begin
  Result := fGuid;
end;

Wie kann ich Result direkt auf fGuid zeigen lassen?
Ich kenne mich mit Pointern^ auf Records zu wenig aus...
Sollte doch aber sicher machbar sein - oder? ;-)

jaenicke 29. Jul 2016 05:30

AW: privaten Record über Getter heraus geben
 
Es genügt, wenn du die Property mit dem Typ PGuid deklarierst. Der Getter muss dann nur einen Pointer auf das private Feld vom Typ TGuid zurückliefern, also @FGuid statt FGuid.

Allerdings sind für den Zweck Klassen deutlich besser geeignet, da damit genau dieses Pointergehampel vermieden wird.

TGuid ist ein etwas unglücklicher Name für einen eigenen Typ, da Delphi selbst diesen Typ schon hat.

stahli 29. Jul 2016 13:06

AW: privaten Record über Getter heraus geben
 
Vielen Dank!

TGuid heißt mein Typ, weil ich im Projekt durchgängig die eigene Guid statt der System-Guid verwende (außer für die Interfaces). Da gibt es also keine Konflikte.

Records habe ich genutzt, weil ich gern die Klassenoperatoren nutzen wollte (habe XE3).

Ich werde wohl doch mal auf eine Klasse umstellen und für die Vergleiche Funktionen aufrufen.
Das scheint mir dann sauberer zu sein.

Stevie 29. Jul 2016 13:44

AW: privaten Record über Getter heraus geben
 
Mach deinen record halt immutable und erlaube nicht, einzelne Felder zu setzen.

Sir Rufo 29. Jul 2016 14:01

AW: privaten Record über Getter heraus geben
 
Oder eine Kombination aus Interface, Instanz und Record:
Delphi-Quellcode:
IFoo = interface
  function GetBar: Integer;
  procedure SetBar( const Value: Integer );
  property Bar : Integer read GetBar write SetBar;
end;

TFoo = record
private
  FFoo: IFoo;
  procedure EnsureInitialized();
  function GetBar: Integer;
  procedure SetBar( const Value: Integer );
public
  property Bar: Integer read GetBar write SetBar;
end;

TFooImpl = class( TInterfacedObject, IFoo )
private { IFoo }
  function GetBar: Integer;
  procedure SetBar( const Value: Integer );
private
  FBar: Integer;
end;

procedure TFoo.EnsureInitialized;
begin
  if not Assigned( FFoo )
  then
    FFoo := TFooImpl.Create;
end;

function TFoo.GetBar: Integer;
begin
  EnsureInitialized();
  Result := FFoo.Bar;
end;

procedure TFoo.SetBar( const Value: Integer );
begin
  EnsureInitialized();
  FFoo.Bar := Value;
end;

function TFooImpl.GetBar: Integer;
begin
  Result := FBar;
end;

procedure TFooImpl.SetBar( const Value: Integer );
begin
  FBar := Value;
end;
Dem Record sollte man dann aber noch eine Clone Methode spendieren, damit man bei Bedarf auch einen unabhängigen Record bekommen kann :stupid:

Stevie 1. Aug 2016 10:15

AW: privaten Record über Getter heraus geben
 
Das funktioniert leider nicht so einfach - du musst immernoch sicher stellen, dass das Interface innerhalb des Records vor dem herausgeben initialisiert ist.

Delphi-Quellcode:
type
  TQux = class
  private
    fFoo: TFoo;
  public
    property Foo: TFoo read fFoo;
  end;

...

var
  qux: TQux;
  foo: TFoo;
begin
  qux := TQux.Create;
  foo := qux.Foo;
  foo.Bar := 42;
  Assert(qux.Foo.Bar = 42); // whoops!

stahli 1. Aug 2016 15:51

AW: privaten Record über Getter heraus geben
 
Danke Euch.

Ich nutze jetzt Interfaces (IsoGuid) und führe Vergleiche über Funktionen durch.

Die Umstellung war recht aufwendig aber ich denke, so geht es jetzt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:51 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