![]() |
AW: Generische Interface-Liste
Hallo,
Zitat:
Delphi-Quellcode:
Und dann ohne Cast.
// Generische Interface-Liste, implementiert generisches InterfaceList-Interface
TGenericInterfaceList<T: IInterface> = class(TInterfacedObject, IGenericInterfaceList<T>) public FInterfaces : TList<T>; function Get(Index: Integer): T; end; einbeliebigername. |
AW: Generische Interface-Liste
Zitat:
|
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:
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.
function TGenericInterfaceList<T>.Get(Index: Integer): T;
begin Result := T(FInterfaces[Index]); end; @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:
|
AW: Generische Interface-Liste
Zitat:
Ich hätte mir vorstellen können, dass man der Liste ein Interface (IBlub) zuweisen muss, statt einem Objekt (TBlub).
Delphi-Quellcode:
... oder so. Ich hätte erwartet, dass der Compiler ein Objekt direkt ablehnt.
// also statt:
BL := TGenericInterfaceList<IBlub>.Create(); BL.Add(TBlub.Create()); // besser: BL := TGenericInterfaceList<IBlub>.Create(); BL.Add(TBlub.Create() as IBlub); Aber ich steige hier erst mal besser wieder aus und rede in 1-2 Jahren wieder zu dem Thema mit. :duck: |
AW: Generische Interface-Liste
Zitat:
|
AW: Generische Interface-Liste
Zitat:
Zitat:
Zitat:
|
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:
"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.
type
TFoo<T> = class FValue: T; function GetAsObject: TObject; end; function TFoo<T>.GetAsObject: TObject; begin Result := TObject(FValue); end; Jedenfalls muss man ab Update 3 dann sowas schreiben:
Delphi-Quellcode:
Wenn du generische Listen mit entsprechenden Interfaces haben möchtest, schau dir eventuell
function TFoo<T>.GetAsObject: TObject;
begin Result := TObject(PPointer(@FValue)^); end; ![]() |
AW: Generische Interface-Liste
Zitat:
|
AW: Generische Interface-Liste
Zitat:
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. |
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 15:02 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