Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Record- oder Klassenfelder als property zuweisen und lesen, wie? (https://www.delphipraxis.net/212545-record-oder-klassenfelder-als-property-zuweisen-und-lesen-wie.html)

delphifan2004 24. Feb 2023 20:04

Record- oder Klassenfelder als property zuweisen und lesen, wie?
 
Hallo,

bitte guckt nicht zu sehr auf meine Ausdrucksweise, ich weiß echt nicht weiter. Fragestellung unten.

Delphi-Quellcode:
  { TDataItem }

  TDataItem = record
    DataType: TDataType;
    Field1: Typ1;
    Field2: Typ2;                     //Für mehrere Datenfelder
    Fieldnum: Integer;                //Feldnummer
    case Longword of
     0: (BinData : Pointer);          //für binäre Daten
     1: (dworddata: Longword);        //für ganzzahlige positive Zahlenwerte
     2: (Int32data: Integer);         //für ganzzahlige positive wie negative Zahlenwerte
     3: (Floatdata: Double);          //für Gleitkommazahlen
     4: (Int16data: smallint);        //für 16 Bit Integerzahlen
     5: (Strgdata : PString);         //für Strings
  end;


  { TGenericItem }

  TGenericItem = class(TObject)
  private
    FData: TDataItem;
    function GetDataType: TDataType;
    function GetData: TDataItem;
    procedure SetDataType(AValue: TDataType);
    procedure SetData(AValue: TDataItem);
  public

    constructor Create;
    destructor Destroy; override;

    property Data: TDataItem read GetData write SetData;

  end;

  { TCustomColumn }

  TCustomColumn = class(TComponent)
  private
    FLeft: Integer;
    FTop: Integer;
    FItem: TGenericItem;
    procedure SetItem(AValue: TGenericItem);
  public
    constructor Create(AOwner: TComponent);
    property [B]Item[/B]: TGenericItem read FItem write SetItem;
  end;
Wie kann ich jetzt mein Item in TCustomColumn lesen und schreiben, ohne dass Exceptions geworfen werden.

Delphi-Quellcode:
function TGridColumn.GetWidth: Integer;
var AItem: TDataItem;
begin
  AItem := Item.Data;           //das hier wird nicht akzeptiert, wie mache ich das besser? Wenn ich an die Eigenschaft nur den ganzen Datentyp zuweisen kann, brauche ich ja die Daten der übrigen Felder
                                 //die hier nicht beeinflusst werden. Ok, beim Getter nicht aber beim Setter.
  Result := AItem.Fieldnum;     //sowas in der Art will ich am Ende haben, für alle im Datentyp enthaltenen Felder
end;
Wie kann ich bei zusammengesetzten Typen die Daten als Eigenschaft lesen uns schreiben. Sorry, ich weiß echt nicht wie ich es anders ausdrücken soll.

Am Ende will ich Record- und Klassentypen als property lesen und schreiben und dabei auch einzelne Datenfelder dieser Typen verändern können, wie im Beispiel die Fieldnum oder die Inhalte von Field1 und Field2, wobei ich als Interface nur die property mit dem gesamten Datentyp habe, der die Felder enthält.

MPeters 25. Feb 2023 07:53

AW: Record- oder Klassenfelder als property zuweisen und lesen, wie?
 
Alles zu kompliziert. Ich baue solche Felder grundsätzlich direkt in meine Klasse ein, vermeide solche komplexen Konstrukte.

jaenicke 25. Feb 2023 10:06

AW: Record- oder Klassenfelder als property zuweisen und lesen, wie?
 
Mit einem Pointer auf TDataItem, den die Property zurück liefert, sollte es gehen.

Ich persönlich würde das ganze aber komplett mit Generics und Klassen umsetzen. Mal so ins Blaue getippt, das sollte kompilieren:
Delphi-Quellcode:
type
  TDataItem = class

  end;

  TDataItem<T> = class(TDataItem)
  private
    FData: T;
  public
    constructor Create(const AValue: T);
    procedure SetData(const AValue: T);
    function GetData: T;
  end;

  TCustomColumn = class(TComponent)
  private
    FItem: TDataItem;
  public
    procedure SetItem<T>(const AValue: T);
    function GetItem<T>: T;
  end;

...

function TCustomColumn.GetItem<T>: T;
begin
  if Assigned(FItem) and (FItem is TDataItem<T>) then
    Result := TDataItem<T>(FItem).GetData
  else
    raise Exception.Create('Falscher Typ');
end;

procedure TCustomColumn.SetItem<T>(const AValue: T);
begin
  FItem.Free;
  FItem := TDataItem<T>.Create(AValue);
end;

constructor TDataItem<T>.Create(const AValue: T);
begin
  FData := AValue;
end;

function TDataItem<T>.GetData: T;
begin
  Result := FData;
end;

procedure TDataItem<T>.SetData(const AValue: T);
begin
  FData := AValue;
end;

...

procedure Example;
var
  a: TCustomColumn;
begin
  a := TCustomColumn.Create(nil);
  a.SetItem<Integer>(42);
  ShowMessage(a.GetItem<Integer>.ToString);
  a.SetItem<string>('42');
  ShowMessage(a.GetItem<string>);
end;
Alternativ:
Delphi-Quellcode:
function TCustomColumn.GetItem<T>: T;
begin
  if Assigned(FItem) then
    Result := (FItem as TDataItem<T>).GetData
  else
    Result := TValue.Empty.AsType<T>;
end;

ConnorMcLeod 25. Feb 2023 10:21

AW: Record- oder Klassenfelder als property zuweisen und lesen, wie?
 
Denke ich zu einfach? Bei mir funkt es ...
Delphi-Quellcode:
function TTemplateApp.GetWidth: Integer;
var
  LoColumn : TCustomColumn;
  LoDataItem: TGenericItem;
begin
  Result := 0;
  LoColumn := TCustomColumn.Create(nil);
  LoDataItem := TGenericItem.Create;
  try
    LoColumn.Item := LoDataItem;
    Result := LoColumn.Item.Data.Int32data;
  finally
    FreeAndNil(LoDataItem);
    FreeAndNil(LoColumn);
  end;
end;

jaenicke 25. Feb 2023 10:45

AW: Record- oder Klassenfelder als property zuweisen und lesen, wie?
 
Zitat:

Zitat von ConnorMcLeod (Beitrag 1519105)
Denke ich zu einfach? Bei mir funkt es ...

Versuch das mal zu schreiben. Du bekommst den Record über die property, aber dadurch ist er readonly. Wenn man den Pointer zurück liefert, wie ich geschrieben habe, müsste es aber gehen.

ConnorMcLeod 25. Feb 2023 12:05

AW: Record- oder Klassenfelder als property zuweisen und lesen, wie?
 
Verstehe, es geht um die Zuweisung. Das habe ich im Anfangsbeispiel nicht gesehen.
Ein Interimsrecord tut's auch.

Delphi-Quellcode:
function TTemplateApp.GetWidth: Integer;
var
  LoColumn : TCustomColumn;
  LoDataItem: TGenericItem;
  LrData     : TDataItem;
begin
  Result := 0;
  LoColumn := TCustomColumn.Create(nil);
  LoDataItem := TGenericItem.Create;
  try // Speicherschutz
    LoColumn.Item := LoDataItem;

    LrData := LoDataItem.Data;
    LrData.Int32data := 42;
    LoDataItem.Data := LrData;

    Result := LoColumn.Item.Data.Int32data;
  finally // aufräumen
    FreeAndNil(LoDataItem);
    FreeAndNil(LoColumn);
  end;
end;

jaenicke 25. Feb 2023 15:35

AW: Record- oder Klassenfelder als property zuweisen und lesen, wie?
 
Das erfüllt die Anforderung nicht so ganz:
Zitat:

Zitat von delphifan2004 (Beitrag 1519089)
Am Ende will ich Record- und Klassentypen als property lesen und schreiben und dabei auch einzelne Datenfelder dieser Typen verändern können, wie im Beispiel die Fieldnum oder die Inhalte von Field1 und Field2, wobei ich als Interface nur die property mit dem gesamten Datentyp habe, der die Felder enthält.

Davon abgesehen fände ich eine solche Lösung beim Neuentwurf einer Klasse nicht schön.

delphifan2004 25. Feb 2023 18:51

AW: Record- oder Klassenfelder als property zuweisen und lesen, wie?
 
Danke @jaenicke, da werd ich das mal so umsetzen, wie in Beitrag #3, das compiliert. Bei Fragen oder endgültig gefundener Lösung melde ich mich wieder. Da werd ich mich also nun mal mit Generics beschaäftigen.


@ConnorMcLeod: so wollte ich das ja zuerst machen, funkt aber bei mir nicht.

ConnorMcLeod 26. Feb 2023 10:33

AW: Record- oder Klassenfelder als property zuweisen und lesen, wie?
 
Gut, wenn die Lösung paßt. Ich bin auch ein Freund von Pointern. Aber die Dereferenziererei und Casterei verlangt eiserne Disziplin ;-)

Uwe Raabe 26. Feb 2023 12:02

AW: Record- oder Klassenfelder als property zuweisen und lesen, wie?
 
Zitat:

Zitat von ConnorMcLeod (Beitrag 1519153)
Aber die Dereferenziererei und Casterei verlangt eiserne Disziplin ;-)

Ist doch gar nicht nötig:
Delphi-Quellcode:
type
  PDataItem = ^TDataItem;
...
type
  TGenericItem = class(TObject)
  private
    FData: TDataItem;
  ...
    property Data: PDataItem read GetData;
...
function TGenericItem.GetData: PDataItem;
begin
  Result := @FData;
end;
...
var Item: TGenericItem;
...
  if Item.Data.Fieldnum < 0 then
    Item.Data.FieldNum := 1;


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