Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Generische Interface-Liste (https://www.delphipraxis.net/166336-generische-interface-liste.html)

einbeliebigername 10. Feb 2012 12:52

AW: Generische Interface-Liste
 
Hallo,

Zitat:

Zitat von s.h.a.r.k (Beitrag 1149913)
Delphi-Quellcode:
// Generische Interface-Liste, implementiert generisches InterfaceList-Interface
TGenericInterfaceList<T: IInterface> = class(TInterfacedObject, IGenericInterfaceList<T>)
public
  FInterfaces : TInterfaceList;
  function Get(Index: Integer): T;
end;

Mit Interfaces in Verbindung mit generischen Listen habe ich zwar noch nichts gemacht aber sollte es nicht so gehen?
Delphi-Quellcode:
// Generische Interface-Liste, implementiert generisches InterfaceList-Interface
TGenericInterfaceList<T: IInterface> = class(TInterfacedObject, IGenericInterfaceList<T>)
public
  FInterfaces : TList<T>;
  function Get(Index: Integer): T;
end;
Und dann ohne Cast.

einbeliebigername.

mjustin 10. Feb 2012 12:56

AW: Generische Interface-Liste
 
Zitat:

Ziel des ganzen soll es sein TInterfaceList durch eine generische, einfachere Liste zu ersetzen.
Ginge das nicht auch mit Generics.Collections.TList<IMeinInterface> ?

Stevie 10. Feb 2012 12:57

AW: Generische Interface-Liste
 
@Stahli: Da das Add von der generischen Liste ist, wird der Wert, der dort reingegeben wird, vom Typ T sein ;)

Lösung:
Delphi-Quellcode:
function TGenericInterfaceList<T>.Get(Index: Integer): T;
begin
  Result := T(FInterfaces[Index]);
end;
Warum kein cast oder Supports? Na, weil das Interface, was du beim Add hineingibst, schon vom Typ T ist, was aber auch ein IInterface ist (Typeconstraint). Deshalb stehen in FInterfaces immer interface Referenzen vom Typ T. Und deshalb kannst du es einfach wieder umcasten.

@XE2 Benutzer:
Hier wurden (mit Update 3 glaube ich) die Typecasts bei Generics etwas restriktiver. Deshalb muss man dort bei manchen solcher Typecasts einen kleinen Umweg über PPointer gehen. Das aber, meine ich mich zu erinnern, nur wenn man von T auf einen konkreten Typ möchte, welcher zwar durch die Programmlogik korrekt ist aber nicht über einen Typeconstraint gegeben ist.


Zitat:

Zitat von mjustin (Beitrag 1150311)
Zitat:

Ziel des ganzen soll es sein TInterfaceList durch eine generische, einfachere Liste zu ersetzen.
Ginge das nicht auch mit Generics.Collections.TList<IMeinInterface> ?

Generics.Collections Klassen haben keine Interfaces.

stahli 10. Feb 2012 14:10

AW: Generische Interface-Liste
 
Zitat:

Zitat von Stevie (Beitrag 1150312)
@Stahli: Da das Add von der generischen Liste ist, wird der Wert, der dort reingegeben wird, vom Typ T sein ;)

Ja epent! :stupid:

Ich hätte mir vorstellen können, dass man der Liste ein Interface (IBlub) zuweisen muss, statt einem Objekt (TBlub).

Delphi-Quellcode:
// also statt:
  BL := TGenericInterfaceList<IBlub>.Create();
  BL.Add(TBlub.Create());

// besser:
  BL := TGenericInterfaceList<IBlub>.Create();
  BL.Add(TBlub.Create() as IBlub);
... oder so. Ich hätte erwartet, dass der Compiler ein Objekt direkt ablehnt.

Aber ich steige hier erst mal besser wieder aus und rede in 1-2 Jahren wieder zu dem Thema mit. :duck:

Stevie 10. Feb 2012 14:31

AW: Generische Interface-Liste
 
Zitat:

Zitat von stahli (Beitrag 1150325)
Zitat:

Zitat von Stevie (Beitrag 1150312)
@Stahli: Da das Add von der generischen Liste ist, wird der Wert, der dort reingegeben wird, vom Typ T sein ;)

Ja epent! :stupid:

Nur, weil da TBlub.Create steht, wird noch lang kein TBlub in Add hineingegeben, sondern ein IBlub, denn das ist in diesem Fall T. Wenn eine Klasse A ein Interface B implementiert, sind Instanzen von Klasse A davon direkt zuweisungskompatibel zu Variablen vom Interface B.

s.h.a.r.k 10. Feb 2012 17:44

AW: Generische Interface-Liste
 
Zitat:

Zitat von Stevie (Beitrag 1150312)
Lösung:
Delphi-Quellcode:
function TGenericInterfaceList<T>.Get(Index: Integer): T;
begin
  Result := T(FInterfaces[Index]);
end;

Genau diese Lösung habe ich ja im Moment und diese funktioniert nicht!

Zitat:

Zitat von Stevie (Beitrag 1150312)
@XE2 Benutzer:
Hier wurden (mit Update 3 glaube ich) die Typecasts bei Generics etwas restriktiver. Deshalb muss man dort bei manchen solcher Typecasts einen kleinen Umweg über PPointer gehen. Das aber, meine ich mich zu erinnern, nur wenn man von T auf einen konkreten Typ möchte, welcher zwar durch die Programmlogik korrekt ist aber nicht über einen Typeconstraint gegeben ist.

Hast du hierzu mehr Informationen? Was genau in Bezug auf PPointer? Ich habe XE2, Update 3 installiert (und ja, ich weiß, dass es Update 4 gibt) und obige Lösung funktioniert leider nicht :evil: Ich habe echt keine Ahnung warum nicht... Sowas nervt ungemein...

Zitat:

Zitat von Stevie (Beitrag 1150312)
Generics.Collections Klassen haben keine Interfaces.

Darüber hatte ich mich ja gewundert und daher habe ich diese Liste entworfen...

Stevie 11. Feb 2012 11:46

AW: Generische Interface-Liste
 
Hätt schwören können, da stand gestern was anderes, egal.

Hab nicht dran gedacht, dass beim Add in die TInterfaceList auch nen QueryInterface gemacht wird, also wird T dann wieder auf IInterface "gecastet". Das musst du dann beim Get wieder umdrehen:

Delphi-Quellcode:
function TGenericInterfaceList<T>.Get(Index: Integer): T;
begin
  FInterfaces[Index].QueryInterface(GetTypeData(TypeInfo(T)).Guid, Result);
end;

Bis XE2 Update 2 ging folgendes:

Delphi-Quellcode:
type
  TFoo<T> = class
    FValue: T;
    function GetAsObject: TObject;
  end;

function TFoo<T>.GetAsObject: TObject;
begin
  Result := TObject(FValue);
end;
"Mach doch nen constraint drauf" mag jemand sagen. Stimmt, solang ich nur Objekte reinpacken will. Eventuell will ich aber Interfaces und Objekte damit verwalten und dann macht sowas eventuell Sinn.

Jedenfalls muss man ab Update 3 dann sowas schreiben:
Delphi-Quellcode:
function TFoo<T>.GetAsObject: TObject;
begin
  Result := TObject(PPointer(@FValue)^);
end;
Wenn du generische Listen mit entsprechenden Interfaces haben möchtest, schau dir eventuell Delphi Coll oder Spring an.

s.h.a.r.k 13. Feb 2012 12:15

AW: Generische Interface-Liste
 
Zitat:

Zitat von Stevie (Beitrag 1150485)
Hätt schwören können, da stand gestern was anderes, egal.

Hab nicht dran gedacht, dass beim Add in die TInterfaceList auch nen QueryInterface gemacht wird, also wird T dann wieder auf IInterface "gecastet". Das musst du dann beim Get wieder umdrehen:

Delphi-Quellcode:
function TGenericInterfaceList<T>.Get(Index: Integer): T;
begin
  FInterfaces[Index].QueryInterface(GetTypeData(TypeInfo(T)).Guid, Result);
end;

Wuhu... Das funktioniert einwandfrei!!! Danke dir vielmals! :thumb: Jetzt weiß ich auch, wie man an die GUID eines Interfaces kommt. Tausend Dank!

stahli 27. Jul 2020 20:24

AW: Generische Interface-Liste
 
Zitat:

Zitat von stahli (Beitrag 1150325)
Aber ich steige hier erst mal besser wieder aus und rede in 1-2 Jahren wieder zu dem Thema mit. :duck:

Jetzt sind es glatt 8 Jahre später und ich hatte jetzt mal das gleiche Problem (und bin bei der Lösungssuche auf den Thread hier gestoßen). ;-)

Mit meinem Projekt bin ich noch nicht ganz zurecht gekommen und habe mal ein kleines Testprojekt aufgebaut, um hier nochmal konkret nachzufragen.
Damit funktioniert es jedoch korrekt... :-)

Also stelle ich es mal hier ein, falls es jemand nachvollziehen möchte bzw. gebrauchen kann:
(Real sind die Klassen natürlich in verschiedene Klassen aufgeteilt, wird eine Factory benutzt usw.)


Delphi-Quellcode:
program GenInterfacesTest;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  Generics.Collections;

type

  // Base

  IItem = interface
    ['{836A887A-1687-4BC3-8534-18BA517D322D}']
    procedure Go;
  end;

  IItemList<T: IItem> = interface(IItem)
    ['{D231E719-50DE-410A-BF54-CC65487B860A}']
    procedure Add(const aItem: T);
    function GetFirstItem: T;
    function _get_Item(Index: Integer): T;
    procedure _set_Item(Index: Integer; aItem: T);
    property Items[Index: Integer]: T read _get_Item write _set_Item; default;
  end;

  TItem = class(TInterfacedObject, IItem)
    procedure Go;
  end;

  TItemList<T: IItem> = class(TItem, IItemList<T>)
    fItems: TList<IItem>;
    procedure Add(const aItem: T);
    function GetFirstItem: T;
    function _get_Item(Index: Integer): T;
    procedure _set_Item(Index: Integer; aItem: T);
    property Items[Index: Integer]: T read _get_Item write _set_Item; default;
    constructor Create; virtual;
    destructor Destroy; override;
  end;

  // Logic

  IZoo = interface;
  TZoo = class;

  IHund = interface;
  THund = class;

  IHundList = interface;
  THundList = class;

  IKatze = interface;
  TKatze = class;

  IKatzeList = interface;
  TKatzeList = class;

  IZoo = interface(IItem)
    ['{428FD0E8-8600-430A-9CE6-AA361509FB54}']
    function _get_HundList: IHundList;
    procedure _set_HundList(const aValue: IHundList);
    property HundList: IHundList read _get_HundList write _set_HundList;
    function _get_KatzeList: IKatzeList;
    procedure _set_KatzeList(const aValue: IKatzeList);
    property KatzeList: IKatzeList read _get_KatzeList write _set_KatzeList;
  end;

  TZoo = class(TItem, IZoo)
    fHundList: IHundList;
    fKatzeList: IKatzeList;
    function _get_HundList: IHundList;
    procedure _set_HundList(const aValue: IHundList);
    property HundList: IHundList read _get_HundList write _set_HundList;
    function _get_KatzeList: IKatzeList;
    procedure _set_KatzeList(const aValue: IKatzeList);
    property KatzeList: IKatzeList read _get_KatzeList write _set_KatzeList;
    constructor Create; virtual;
    destructor Destroy; override;
  end;

  IHund = interface(IItem)
    ['{956269E2-F70B-4499-B18B-0492CF47CA5B}']
    procedure Wuff;
  end;

  IHundList = interface(IItemList<IHund>)
    ['{331D5BD0-8568-47B5-886D-417BCDAC23B9}']
  end;

  THund = class(TItem, IHund)
    procedure Wuff;
  end;

  THundList = class(TItemList<IHund>, IHundList)
  end;

  IKatze = interface(IItem)
    ['{1D834E0A-1A69-4D7C-9817-F60EE75C4ACB}']
    procedure Miau;
  end;

  IKatzeList = interface(IItemList<IKatze>)
    ['{EC5E64F4-88D5-4E25-9E4C-50F79F0F9395}']
  end;

  TKatze = class(TItem, IKatze)
    procedure Miau;
  end;

  TKatzeList = class(TItemList<IKatze>, IKatzeList)
  end;

var
  Zoo: IZoo;
  Hund: IHund;
  Katze: IKatze;

  { TItem }

procedure TItem.Go;
begin
  //
end;

{ TItemList<T> }

procedure TItemList<T>.Add(const aItem: T);
begin
  fItems.Add(aItem);
end;

constructor TItemList<T>.Create;
begin
  fItems := TList<IItem>.Create;
end;

destructor TItemList<T>.Destroy;
begin
  fItems.Free;
  inherited;
end;

function TItemList<T>.GetFirstItem: T;
begin
  Result := T(fItems[0]);
end;

function TItemList<T>._get_Item(Index: Integer): T;
begin
  Result := T(fItems[Index]);
end;

procedure TItemList<T>._set_Item(Index: Integer; aItem: T);
begin
  fItems[Index] := aItem;
end;

{ TZoo }

constructor TZoo.Create;
begin
  HundList := THundList.Create;
  KatzeList := TKatzeList.Create;
end;

destructor TZoo.Destroy;
begin
  HundList := nil;
  KatzeList := nil;
  inherited;
end;

function TZoo._get_HundList: IHundList;
begin
  Result := fHundList;
end;

function TZoo._get_KatzeList: IKatzeList;
begin
  Result := fKatzeList;
end;

procedure TZoo._set_HundList(const aValue: IHundList);
begin
  fHundList := aValue;
end;

procedure TZoo._set_KatzeList(const aValue: IKatzeList);
begin
  fKatzeList := aValue;
end;

{ THund }

procedure THund.Wuff;
begin
  //
end;

{ TKatze }

procedure TKatze.Miau;
begin
  //
end;

begin

  Zoo := TZoo.Create;

  Hund := THund.Create;
  Zoo.HundList.Add(Hund);

  Katze := TKatze.Create;
  Zoo.KatzeList.Add(Katze);

  Hund := Zoo.HundList.GetFirstItem;
  Katze := Zoo.KatzeList.GetFirstItem;

  Zoo.HundList[0] := Hund;
  Hund := Zoo.HundList[0];

  Zoo.KatzeList[0] := Katze;
  Katze := Zoo.KatzeList[0];

end.

himitsu 27. Jul 2020 20:55

AW: Generische Interface-Liste
 
Eigentlich kann es nicht so richtig funktionieren.
Jedenfalls hätte man so im Minimum mehrfach die selbe GUID im System, was ein bissl dem System der Interfaces wiederspricht.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:04 Uhr.
Seite 2 von 3     12 3      

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