Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Zeiger als Parameter eines generischen Typs, TRecordList (https://www.delphipraxis.net/131738-zeiger-als-parameter-eines-generischen-typs-trecordlist.html)

Panthrax 30. Mär 2009 10:44


Zeiger als Parameter eines generischen Typs, TRecordList
 
Ich überlege, wie weit mir Generika helfen, meine Klassen zu verbessern. In folgendem Fall möchte ich meine Klasse TRecordList als generische Klasse implementieren. TRecordList verwaltet eine Liste Records. P soll der Typparameter sein, z.B. PMyRecord = ^TMyRecord. Problematisch sind die Zuweisungen der Zeiger aus der gekapselten Liste (property List: TList read FList) an Result: P (in GetItem) und von Value: P (in SetItem):
Delphi-Quellcode:
function TRecordList

.GetItem(const Index: Integer): P;
begin
  Pointer(Result):=List[Index];
end;

procedure TRecordList

.SetItem(const Index: Integer; const Value: P);
begin
  List[Index]:=Value;
end;
Problematisch ist, dass ich keine Möglichkeit kenne, die möglichen Typparameterwerte auf Zeiger einzugrenzen. Entprechend muss der Compiler die Zuweisungen bemängeln.

Kann man die Werte irgendwie eingrenzen? Oder, wie kann man Zuweisungen zwischen einem Zeiger und einer Variable "unbekannten Typs" (aber es soll ein Zeiger sein) durchführen?

Hier noch einmal der Quelltext im Zusammenhang, so wie ich mir das vorstelle (auf das Nötige gekürzt). Leider dürfte das in den Methoden GetItem, SetItem, GetRecordSize nicht funktionieren, wenn ich mir vorstelle, dass P eben nicht nur für einen Zeiger stehen kann, sondern auch für eine Zahl, einen String, eine Klasse, eine Schnittstelle,... ("Dürfte" deshalb, weil ich es selbst nicht probieren kann.)
Delphi-Quellcode:
unit RecordList;

interface

uses
  Classes;

type
  TRecordList

 = class
    strict private
    FList: TList;

    strict protected
    property List: TList read FList;

    function GetItem(const Index: Integer): P;
    function GetRecordSize: Integer;
    procedure SetItem(const Index: Integer; const Value: P);

    public
    property Items[const Index: Integer]: P read GetItem write SetItem; default;
    property RecordSize: Integer read GetRecordSize;

    constructor Create;
    destructor Destroy; override;
  end;

  TMyRecord = record
    { ... }
  end;
  PMyRecord = ^TMyRecord;
  TMyRecordList = TRecordList<PMyRecord>;

implementation

{ TRecordList

 }

constructor TRecordList

.Create;
begin
  inherited Create;
  FList:=TList.Create;
end;

destructor TRecordList

.Destroy;
begin
  List.Free;
  inherited;
end;

function TRecordList

.GetItem(const Index: Integer): P;
begin
  Pointer(Result):=List[Index];
end;

function TRecordList

.GetRecordSize: Integer;
begin
  Result:=SizeOf(P^);
end;

procedure TRecordList

.SetItem(const Index: Integer; const Value: P);
begin
  List[Index]:=Value;
end;

end.

Panthrax 2. Apr 2009 13:32

Re: Zeiger als Parameter eines generischen Typs, TRecordList
 
Heißt das, es gibt keine Lösung, oder es weiß keiner eine Lösung? :gruebel:

shmia 2. Apr 2009 13:37

Re: Zeiger als Parameter eines generischen Typs, TRecordList
 
Warum müssen es Records sein?
Nimm doch TObjectList als Ausgangspunkt.

jfheins 2. Apr 2009 13:38

Re: Zeiger als Parameter eines generischen Typs, TRecordList
 
Wäre es nicht sinnvoller, als Typparameter den eigentlichen Record zu übergeben statt einem Pointer darauf?

Panthrax 2. Apr 2009 13:56

Re: Zeiger als Parameter eines generischen Typs, TRecordList
 
Zitat:

Zitat von shmia
Warum müssen es Records sein?
Nimm doch TObjectList als Ausgangspunkt.

Records sind völlig ausreichend und haben den Geschwindigkeitsvorteil ggü. Objekten -- New und Dispose vs. Create und Destroy. Es geht auch darum, die Daten über das Netzwerk zu schicken -- Stream.Write(RecPtr^,SizeOf(TRecord)) vs. eigene Schreibmethode pro Typ.

Zitat:

Zitat von jfheins
Wäre es nicht sinnvoller, als Typparameter den eigentlichen Record zu übergeben statt einen Pointer darauf?

Nein, denn dann würde Items[I].RecordFeld := Wert nicht mehr den Record in der Liste ändern, sondern nur eine Kopie. Außerdem lässt sich so einfach TList nutzen.

Elvis 2. Apr 2009 14:55

Re: Zeiger als Parameter eines generischen Typs, TRecordList
 
Zitat:

Zitat von Panthrax
Zitat:

Zitat von jfheins
Wäre es nicht sinnvoller, als Typparameter den eigentlichen Record zu übergeben statt einen Pointer darauf?

Nein, denn dann würde Items[I].RecordFeld := Wert nicht mehr den Record in der Liste ändern, sondern nur eine Kopie. Außerdem lässt sich so einfach TList nutzen.

So hat er das wohl nicht gemeint.

Geht das hier?
Delphi-Quellcode:
type TRecordList<T> = class(T:record)
  type PItemType = ^T;
  ...
  function GetItem(const Index: Integer): PItemType;
end;
Oder das?
Delphi-Quellcode:
type TRecordList<T> = class(T:record)
  ...
  function GetItem(const Index: Integer): ^T;
end;

Panthrax 2. Apr 2009 16:46

Re: Zeiger als Parameter eines generischen Typs, TRecordList
 
Ok, ich denke, so etwas müsste die Lösung sein:
Delphi-Quellcode:
type
  TRecordList<T: record> = class
    type
      TRecPtr = ^T;
    { ... }
  end;
Vielen Dank für den Hinweis! An diese Möglichkeit hatte ich nicht gedacht.

Leider funktioniert das aber nicht (Quelltext siehe unten):
Zitat:

Zitat von Compiler (Delphi 2009, Update 1 und 2)
[DCC Fataler Fehler] RecordList.pas(72): F2084 Interner Fehler: AV21B654E9-R00000000-0

Der Compilerlauf ist fehlerfrei, wenn GetItem und SetItem nicht deklariert sind. Überhaupt, es scheint mir es leicht zu sein, den Compiler zum Absturz zu bringen. Tja, was tun?

Delphi-Quellcode:
unit RecordList;

interface

uses
  Classes;

type
  TRecordList<T> = class
    public
    type
      TRecPtr = ^T;

    strict private
    FList: TList;

    strict protected
    property List: TList read FList;

    function GetItem(const Index: Integer): TRecPtr;
    function GetRecordSize: Integer;
    procedure SetItem(const Index: Integer; const Value: TRecPtr);

    public
//    property Items[const Index: Integer]: TRecPtr read GetItem write SetItem; default;
    property RecordSize: Integer read GetRecordSize;

    constructor Create;
    destructor Destroy; override;
  end;

  TMyRecord = record
    { ... }
  end;

  PMyRecord = ^TMyRecord;
  TMyRecordList = TRecordList<PMyRecord>;

implementation

{ TRecordList<T> }

constructor TRecordList<T>.Create;
begin
  inherited Create;
  FList:=TList.Create;
end;

destructor TRecordList<T>.Destroy;
begin
  List.Free;
  inherited;
end;

function TRecordList<T>.GetItem(const Index: Integer): TRecPtr;
begin
//  Result := List[Index];
end;

function TRecordList<T>.GetRecordSize: Integer;
begin
  Result := SizeOf(T);
end;

procedure TRecordList<T>.SetItem(const Index: Integer; const Value: TRecPtr);
begin
//  List[Index] := Value;
end;

end.

jfheins 2. Apr 2009 16:59

Re: Zeiger als Parameter eines generischen Typs, TRecordList
 
http://qc.embarcadero.com/wc/qcmain.aspx?d=66577 :stupid:

Panthrax 2. Apr 2009 17:11

Re: Zeiger als Parameter eines generischen Typs, TRecordList
 
Zitat:

Zitat von jfheins
http://qc.embarcadero.com/wc/qcmain.aspx?d=66577 :stupid:

Ganz genau!

Ärgerlich, auf QC ergießen sich die Fehlermeldungen über den Compiler... :wall: :roll:


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