AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi generische Liste als Parameter, Vererbung

generische Liste als Parameter, Vererbung

Ein Thema von haentschman · begonnen am 7. Jul 2015 · letzter Beitrag vom 7. Jul 2015
Antwort Antwort
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.275 Beiträge
 
Delphi 12 Athens
 
#1

generische Liste als Parameter, Vererbung

  Alt 7. Jul 2015, 14:23
Delphi-Version: XE
Hallo alle...

Ich habe mehrere generische Listen welche von einer "Basis" Liste abgeleitet sind.
Delphi-Quellcode:
TListBasis<T: class> = class(TObjectList<T>)
public
  constructor Create; virtual;
end;

TList1 = TListBasis<TBlubb>
TList2 = TListBasis<TBla>
Jetzt wollte ich ein Event bauen was bei einer Änderung egal welcher Liste gefeuert wird. Der Empfänger soll dann schauen um welche Liste es sich handelt und entsprechend weiterverarbeiten.
Delphi-Quellcode:
TOnLoadListEvent = procedure (Sender: TObject; aList: TListBasis<T>) of object;

if Assigned(FOnLoadList) then
begin
  FOnLoadList(Self, FList2); // FList2 = Instanz von TList2
end;
...resultiert in:
Zitat:
[DCC Fehler] dAV3_Preferences.pas(14): E2003 Undeklarierter Bezeichner: 'T'
Wo liegt mein Denkfehler? Geht das überhaupt? Welche Alternativen gibt es?

Danke...
  Mit Zitat antworten Zitat
Photoner

Registriert seit: 6. Dez 2012
Ort: Nürnberg
103 Beiträge
 
Delphi 10.1 Berlin Starter
 
#2

AW: generische Liste als Parameter, Vererbung

  Alt 7. Jul 2015, 14:35
TListBasis<T: class> != TListBasis<T> was passiert wenn du das in ersteres änderst?
Chris
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.275 Beiträge
 
Delphi 12 Athens
 
#3

AW: generische Liste als Parameter, Vererbung

  Alt 7. Jul 2015, 14:40
Danke für die Rückmeldung.

Ich habe schon diverse Varianten durch. Diese auch. Ich suche schon den Vormittag nach meinem Denkfehler. Ich denke langsam, das das nicht möglich ist.
  Mit Zitat antworten Zitat
Photoner

Registriert seit: 6. Dez 2012
Ort: Nürnberg
103 Beiträge
 
Delphi 10.1 Berlin Starter
 
#4

AW: generische Liste als Parameter, Vererbung

  Alt 7. Jul 2015, 15:06
habs:

TOnLoadListEvent<T> = procedure (Sender: TObject; aList: TListBasis<T>) of object; Einsatzbeispiel:

Delphi-Quellcode:
  private
    FOnLoadList : TOnLoadListEvent<TBla>;
    { Private-Deklarationen }
  public
    property OnLoadList : TOnLoadListEvent<TBla> read FOnLoadList write FOnLoadList;
-----------------------------------------------------------------------------------

Was nicht geht:

Delphi-Quellcode:
  private
    FOnLoadList : TOnLoadListEvent<T>;
    { Private-Deklarationen }
  public
    property OnLoadList : TOnLoadListEvent<T> read FOnLoadList write FOnLoadList;
da gibt es einen Fehler:

[dcc32 Fehler] Unit2.pas(27): E2511 Typparameter 'T' muss ein Klassentyp sein
Chris
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.275 Beiträge
 
Delphi 12 Athens
 
#5

AW: generische Liste als Parameter, Vererbung

  Alt 7. Jul 2015, 16:06
Danke für deine Bemühungen...

Tja, da kann man dem Event aber nur TBla übergeben. Es sollte aber auch TBlubb gehen. Deshalb hatte ich das über den "Vorfahr" versucht.
Alternative wäre für jeden Listentyp ein getrenntes Event.
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.007 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#6

AW: generische Liste als Parameter, Vererbung

  Alt 7. Jul 2015, 16:33
Klarer Fall von "hier fehlt uns die Covarianz in Delphi"
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie ( 7. Jul 2015 um 16:36 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.091 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: generische Liste als Parameter, Vererbung

  Alt 7. Jul 2015, 16:51
Ich verstehe nicht wo hier Kovarianz ins Spiel kommt. Wir leiten doch hier nirgendwo von TListBasis<T> ab. Seine Motivation ist dass seine TList1 und TList2 -Instanzen auch ein Event haben, dessen Parameter TBlubb bzw. TBla -Instanzen sind.

Und das ist doch so gegeben, oder?

Delphi-Quellcode:
   TListBasis<T: class> = class(TObjectList<T>)
      public type
         TOnLoadListEvent = TProc<TObject, TListBasis<T>>;
      public var
         OnLoadList: TOnLoadListEvent;
   end;

   TBlubb = class(TObject);
   TBla = class(TObject);

   TList1 = TListBasis<TBlubb>;
   TList2 = TListBasis<TBla>;
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.007 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#8

AW: generische Liste als Parameter, Vererbung

  Alt 7. Jul 2015, 16:56
Die Kovarianz kommt ins Spiel, sobald ich eine TList<derived> als TList<base> behandeln will um ebend nicht für jeden Typen in der Liste einen Speziellen Event Handler zu haben.
Warum? Weil dann jeder, der mal an dieses Event gehen möchte, einen Event handler für genau diesen Typ in der Liste implementieren muss.

Und nebenbei bemerkt und leicht off topic ist es keine gute Idee, ein Event als anonyme Methode zu implementieren.

Allerdings fehlt atm noch die Information, warum der Event handler die Liste braucht. Was wird damit gemacht?

Hier mal hingeschludert, wie über ein Interface (wie in meinem Blogpost erklärt) ein sicherer Lesezugriff auf eine generische Objectliste realisiert werden kann.

Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

uses
  Generics.Collections,
  SysUtils;

type
  IReadOnlyObjectList = interface
    ['{3DFBDE4F-16A4-4395-AB29-58671BD7EC1E}']
    function GetClassType: TClass;
    function GetCount: Integer;
    function GetItem(Index: Integer): TObject;
    function GetEnumerator: TEnumerator<TObject>;
    property ClassType: TClass read GetClassType;
    property Count: Integer read GetCount;
    property Items[Index: Integer]: TObject read GetItem; default;
  end;

  TListBasis<T: class> = class(TObjectList<T>, IReadOnlyObjectList)
  private
    function GetClassType: TClass;
    function GetCount: Integer;
    function GetItem(Index: Integer): TObject;
    function GetEnumerator: TEnumerator<TObject>;
  protected
    function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
    constructor Create; virtual;
  end;

{ TListBasis<T> }

constructor TListBasis<T>.Create;
begin
  inherited Create;
end;

function TListBasis<T>.GetClassType: TClass;
begin
  Result := T;
end;

function TListBasis<T>.GetCount: Integer;
begin
  Result := inherited Count;
end;

function TListBasis<T>.GetEnumerator: TEnumerator<TObject>;
begin
  Result := TEnumerator<TObject>(inherited GetEnumerator);
end;

function TListBasis<T>.GetItem(Index: Integer): TObject;
begin
  Result := TObject(inherited Items[Index]);
end;

function TListBasis<T>.QueryInterface(const IID: TGUID; out Obj): HRESULT;
begin
  if GetInterface(IID, obj) then
    Result := S_OK
  else
    Result := E_NOINTERFACE;
end;

function TListBasis<T>._AddRef: Integer;
begin
  Result := -1;
end;

function TListBasis<T>._Release: Integer;
begin
  Result := -1;
end;

type
  TOnLoadListEvent = procedure (Sender: TObject; const aList: IReadOnlyObjectList) of object;

  TBla = class
  end;

  TTest = class
  private
    FOnLoadList: TOnLoadListEvent;
    FList: TListBasis<TBla>;
    procedure LoadListHandler(Sender: TObject; const aList: IReadOnlyObjectList);
  public
    constructor Create;
    destructor Destroy; override;
    procedure LoadStuff;
  end;

{ TTest }

constructor TTest.Create;
begin
  inherited Create;
  FList := TListBasis<TBla>.Create;

  FOnLoadList := LoadListHandler;
end;

destructor TTest.Destroy;
begin
  FList.Free;
  inherited;
end;

procedure TTest.LoadListHandler(Sender: TObject; const aList: IReadOnlyObjectList);
var
  obj: TObject;
begin
  Writeln(aList.Count, ' items of type ', aList.ClassType.ClassName);
end;

procedure TTest.LoadStuff;
begin
  FList.AddRange([TBla.Create, TBla.Create, TBla.Create, TBla.Create]);
  if Assigned(FOnLoadList) then
    FOnLoadList(Self, FList);
end;

var
  test: TTest;
begin
  try
    test := TTest.Create;
    try
      test.LoadStuff;
    finally
      test.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie ( 7. Jul 2015 um 19:06 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.275 Beiträge
 
Delphi 12 Athens
 
#9

AW: generische Liste als Parameter, Vererbung

  Alt 7. Jul 2015, 17:28
Hallo alle...
Zitat:
Allerdings fehlt atm noch die Information, warum der Event handler die Liste braucht. Was wird damit gemacht?
Der Hintergrund ist folgender. Der Empfänger des Events, in diesem Falle die Form, stellt den Inhalt der Listen dar. Es sollte ein Eventhandler für alle Listen sein. Im Eventhandler sollte dann über die Listenklasse entschieden werden welches "View" gefüllt wird. Prinpiell ist der Form auch der Lagerplatz der Listen bekannt. Den Inhalt direkt von dort zu beziehen wäre auch nicht das Problem. Ich arbeite aber lieber mit Events, da man dann ggf. das Laden auch in einen Thread auslagern kann und der Thread Bescheid sagt wenn die Daten da sind. Da braucht dann die Anzeigelogik nicht geändert werden.
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:24 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