[Gelöst] Generische Liste (TFPGList) in Generic verwenden

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

[Gelöst] Generische Liste (TFPGList) in Generic verwenden

Beitrag von Nimral »

Ich möchte in einem Generic eine TFPGList verwenden. Eigentlich müsste das ungefähr so funktionieren:

Code: Alles auswählen

unit Unit1;

{$mode objfpc}{$H+}
{$modeswitch advancedrecords}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, FGL;

Type

  { TSomeGeneric }

  generic TSomeGeneric<T> = class
    private
      FCache: specialize TFPGList<T>;
    public
      procedure add(Const ARec:T);
      constructor create;
      destructor destroy;
  end;

Type
  TRecOne = Record
            CreatedAt,ModifiedAt: TDateTime;
            Content:ShortString;
            class operator=(R1,R2:TRecOne):boolean;
  end;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FTestList: specialize TSomeGeneric<TRecOne>;
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TRecOne }

class operator TrecOne.=(R1,R2:TRecOne):boolean;
begin
  result := (R1.Content = R2.Content) and (R1.ModifiedAt = R2.ModifiedAt);
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);

var
  R:TRecOne;

begin
  R.CreatedAt := Now();
  R.ModifiedAt := 0;
  R.Content := 'Record created: ' + DateTimeToStr(R.CreatedAt);
  FTestList.Add(R);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FTestList := specialize TSomeGeneric<TRecOne>.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FTestList);
end;

{ SomeGeneric }

procedure TSomeGeneric.add(const ARec: T);

begin
  FCache.Add(ARec);
end;

constructor TSomeGeneric.create;

begin
  // FCache := specialize TFPGList<T>.Create;
end;

destructor TSomeGeneric.destroy;

begin
  FreeAndNil(FCache);
end;

end.
Problem siehe TSomeGeneric.create: wie instanziiere ich die FCache Variable? So wie im Kommentar gehts mal nicht. Separaten Datentypen definieren kann ich auch nicht, weil dann <T> nicht mehr zur Verfügung steht. wie muss man die Struktur aufbauen, um die FCache Liste richtig instantiieren zu können?

Thx, Armin.
Zuletzt geändert von Nimral am Do 8. Jul 2021, 13:26, insgesamt 1-mal geändert.

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: Generische Liste (TFPGList) in Generic verwenden

Beitrag von Nimral »

Ich habs selber gefunden, man kann Typen auch innerhalb von generics definierien.

Code: Alles auswählen


unit Unit1;

{$mode objfpc}{$H+}
{$modeswitch advancedrecords}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls,
  FGL;

Type

  { TSomeGeneric }

  generic TSomeGeneric<T> = class
    Type TGenericList = specialize TFPGList<T>;
    private
      FCache: TGenericList;
    public
      procedure add(Const ARec:T);
      constructor create;
      destructor destroy;
  end;

Type
  TRecOne = Record
            CreatedAt,ModifiedAt: TDateTime;
            Content:ShortString;
            class operator=(R1,R2:TRecOne):boolean;
  end;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    StatusBar1: TStatusBar;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FTestList: specialize TSomeGeneric<TRecOne>;
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TRecOne }

class operator TrecOne.=(R1,R2:TRecOne):boolean;
begin
  result := (R1.Content = R2.Content) and (R1.ModifiedAt = R2.ModifiedAt);
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);

var
  R:TRecOne;

begin
  R.CreatedAt := Now();
  R.ModifiedAt := 0;
  R.Content := 'Record created: ' + DateTimeToStr(R.CreatedAt);
  FTestList.Add(R);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FTestList := specialize TSomeGeneric<TRecOne>.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FTestList);
end;

{ SomeGeneric }

procedure TSomeGeneric.add(const ARec: T);

begin
  FCache.Add(ARec);
  Form1.StatusBar1.SimpleText := Format({$I %CURRENTROUTINE%} + ': %s %d',['Records: ',FCache.Count]);
end;

constructor TSomeGeneric.create;

begin
  FCache := TGenericList.Create;
end;

destructor TSomeGeneric.destroy;

begin
  FreeAndNil(FCache);
end;

end.
Hg, Armin.

PascalDragon
Beiträge: 830
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: [Gelöst] Generische Liste (TFPGList) in Generic verwenden

Beitrag von PascalDragon »

Theoretisch sollte deine erste Variante auch gehen, aber da ist noch ein Bug, der das aktuell verhindert (wurde bereits gemeldet).
FPC Compiler Entwickler

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: [Gelöst] Generische Liste (TFPGList) in Generic verwenden

Beitrag von Nimral »

Wie würde das dann künftig konkret formuliert werden?

Code: Alles auswählen

    FCache := TFPGList<T>.Create;
Rechts im Create muss ja IMHO immer ein Type hin, da schiene mir das der einzige konsistente Ansatz der mir auf Anhieb einfällt, wenn ich keinen eigenen Typen definieren müssen soll ...

Armin.

PascalDragon
Beiträge: 830
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: [Gelöst] Generische Liste (TFPGList) in Generic verwenden

Beitrag von PascalDragon »

Genau so, wie es in deinem Kommentar im ersten Beispiel steht:

Code: Alles auswählen

FCache := specialize TFPGList<T>.Create;
In den nicht-Delphi modi ist eine Spezialisierung definiert als SPECIALIZE IDENTIFIER<TYPE [, TYPE[, …]]>.
FPC Compiler Entwickler

Antworten