![]() |
Generische Ableitung TList<>
Liste der Anhänge anzeigen (Anzahl: 1)
Toll die Spracherweiterung für generische Typen in D2009!
Nur, bei meiner ersten Anwendung einer TList<> Ableitung habe ich leider erste Schwierigkeiten. Denn ich möchte eine neue TList<> Ableitung erstellen, welche auf einer eignen Elementen-Klasse basiert, die nur ein ID-Property enthält, um später in der neuen List-Klasse nach dieser ID zu suchen:
Delphi-Quellcode:
In der neuen Liste möchte ich abgeleitete Klassen von TMyBase
TMyBase = class
strict private fID: string; public constructor Create(ID: string); property ID: string read fID; end; constructor TMyBase.Create(ID: string); begin fID := ID; end; ablegen und mit einer neuen Methode FindByID wieder finden.
Delphi-Quellcode:
Dies läuft so weit, nur scheint mir die nötige Typenkonvertierung
TMyList<T> = class(TList<TMyBase>)
public function FindByID(ID: string): TMyBase; end; function TMyList<T>.FindByID(ID: string): TMyBase; var c: integer; begin result := nil; for c := 0 to Count - 1 do if (Items[c] as TMyBase).ID = ID then result := Items[c]; end; Items[c] as TMyBase fraglich. Wenn ich jetzt eine Ableitung von TMyBase mache, sind in der Anwendung weitere Konvertierungen nötig:
Delphi-Quellcode:
Die Anwendung:
TMyName = class(TMyBase)
strict private fName: string; public constructor Create(ID, aName: string); property Name: string read fName; end; constructor TMyName.Create(ID, aName: string); begin inherited Create(ID); fName := aName; end;
Delphi-Quellcode:
Auch hier sollte meines erachtens die Typenonvertierung
UseMyList := TMyList<TMyName>.Create;
UseMyList.Add(TMyName.Create('ID-1', 'Meier')); UseMyList.Add(TMyName.Create('ID-2', 'Müller')); UseMyList.Add(TMyName.Create('ID-3', 'Tester')); MyString := (UseMyList.FindByID('ID-3') as TMyName).Name; (UseMyList.FindByID('ID-3') as TMyName) nicht mehr nötig sein, damit das generische Konzept richtig umgesetzt wird. Meine Vermutung ist, dass ich die FindByID Methode falsch deklariert habe, und dass der Rückgabe-Typ hier <T> sein müsste. Leider bekomme ich mit folgender Deklaration in D2009 neue Probleme, weil TMyBase nicht von T abgeleitet ist (und ich auch keinen Weg fand, dies zu tun).
Delphi-Quellcode:
Bei einer echten Anwendung mit Duzenden von Ableitungen wird diese kleine
TMyList<T> = class(TList<TMyBase>)
public function FindByID(ID: string): T; end; Unschönheit schnell zur grösseren Fehlerquelle. Deshalb möchte ich meinen ersten Ansatz hinterfragen lassen. Beiliegend die kurze Konsolen-Applikation zum Experimentieren, damit meine Abhandlung nicht reine Theorie bleibt. Danke für eure Lösungen. Gruss Christoph BTW: Refactoring von Klassennamen welche als Generische Typen verwendet werden (hier TMyBase) scheint in D2009 (noch) nicht zu funktionieren. Gibt es einen Workaround? |
Re: Generische Ableitung TList<>
Unterstützt Delphi keine generic constraints? Das wäre tödlich.. :?
Delphi-Quellcode:
TMyList<T: TMyBase> = class(TList<T>)
|
Re: Generische Ableitung TList<>
Liste der Anhänge anzeigen (Anzahl: 1)
Doch, genau das ist es! Damit lässt sicher das Problem lösen.
Jetzt habe ich nur noch ein weiteres Problem mit der Typenzuweisung result := nil:
Delphi-Quellcode:
Ich bin sicher, auch hierfür muss es eine Lösung geben!
TMyList<T: TMyBase> = class(TList<T>)
public function FindByID(ID: string): T; end; function TMyList<T>.FindByID(ID: string): T; var c: integer; begin // result := nil; -> DCC Error: E2010 Incompatible types: T and pointer for c := 0 to Count - 1 do if Items[c].ID = ID then result := Items[c]; end; Erstmal Besten Dank an Dax! |
Re: Generische Ableitung TList<>
Probier mal, ob es auch "T: class, TMyBase" oder etwas ähnliches annimmt - ansonsten dringend in die Sprachbeschreibung schauen ;) Mit den Delphi-Generics kenne ich mich nun leider garnicht aus, dass constraints so notiert werden wie oben hab' ich auch nur aus einem Blog aufgeschnappt.
|
Re: Generische Ableitung TList<>
OT:
Nach dem ersten 30 Sekunden langen Blick scheint mir die Delphi Implementation von Generics unnötig kompliziert. So der erste Eindruck. OnToppic: Probiere es mit :
Delphi-Quellcode:
Result := TObject(nil);
|
Re: Generische Ableitung TList<>
Zitat:
|
Re: Generische Ableitung TList<>
Leider erlaubt dies der Compiler nicht:
result := TObject(nil); -> E2010: Incompatible Types T and TObject Die Situation verändert sich auch nicht, wenn ich die veraltete Deklaration der Basis-Klasse anwende: TMyBase = class(TObject) Natürlich läuft auch der naheliegende Typcast nicht result := T(nil); -> E2089: Invalid Typcast Auch der Versuch mit der neuen Exit-Clause, die einen Rückgabe-Parameter erlaubt geht nicht: exit(nil); -> E2010: Incompatible Types T and Pointer Ich bin ratlos, kann mir aber nicht vorstellen, dass dieses Triviale Konstrukt nicht lösbar sein sollte. |
Re: Generische Ableitung TList<>
Zitat:
|
Re: Generische Ableitung TList<>
Liste der Anhänge anzeigen (Anzahl: 1)
Super, damit lässt sich auch das letzte Problem elegant lösen!
Gerne bilde ich die korrigierte Klasse TMyList nochmals vollständig ab. Im Anhang lege gleich noch das ganze Konsolen-Projekt bei.
Delphi-Quellcode:
Danke an alle für die Tatkräftige Unterstützung!
type
TMyList<T: TMyBase> = class(TList<T>) public function FindByID(ID: string): T; end; function TMyList<T>.FindByID(ID: string): T; var c: integer; begin result := Default(T); for c := 0 to Count - 1 do if Items[c].ID = ID then result := Items[c]; end; Das Help von D2009 ist im Vergleich zu D2005-D2007 spürbar besser. Leider enthalten die Kapitel Overview of Generics und folgende aber keine Hinweise zu dieser neuen Funktion Default. Auch sonst finde ich keinen passenden Hinweis. Im Kapitel Generic-Contraints sind alle Beispiele mit Interface Klassen geführt, weswegen ich nicht gleich auf die TMyList<T: TMyBase> kam. Kennt Ihr eine gute Einführung in Generics von Delphi auf dem Netz? |
Re: Generische Ableitung TList<>
Zitat:
|
Re: Generische Ableitung TList<>
Zitat:
|
Re: Generische Ableitung TList<>
Default ist halt die allgemeine Lösung, die Du auch dann nutzen kannst, wenn keine Constriants da sind und es sich bei dem Datentyp um eine Klasse, einen String oder einen Integer handeln könnte.
|
AW: Re: Generische Ableitung TList<>
Da FindByID sowieso zur Klasse TMyBase gehört und FindByID ausschließlich eine Lösung für TMyBase darstellt und Generics an der Stelle nicht mehr benötigt werden, finde ich den Weg unnötig kompliziert.
So fände ich es "logischer"
Delphi-Quellcode:
type
TMyListSpecific = TList<TMyBase>; TMyList = class(TMyListSpecific) public constructor create; destructor destroy; override; function FindByID(ID : string) : TMyBase; end; function TMyList.FindByID(ID: string): TMyBase; var c: integer; begin result := nil; for c := 0 to Count - 1 do if Items[c].ID = ID then result := Items[c]; end; |
AW: Generische Ableitung TList<>
Ein break oder exit bei Fund würde die Sache ggf. noch beschleunigen, falls das nach 6 Jahren überhaupt noch interessiert.
|
AW: Generische Ableitung TList<>
Es ging mir nur um die Vollständigkeit, dass solche Quelltextbeispiele nicht im Raum stehen gelassen werden ;-)
Meiner Meinung nach schoss die ursprüngliche Lösung am Ziel vorbei. |
AW: Generische Ableitung TList<>
Joar, falls mal jemand auf die irrwitzige Idee kommt und die SuFu benutzt. :stupid:
Alternative Lösung: Eine andere Art von Liste verwenden. TListObject<T> = Warum wurde hier TList<> verwendet, wo darin doch Objekte abgelegt werden? Und wer kümmert sich eigentlich um deren Freigabe? TCollection<T> = Gibt es leider nicht, aber als TCollection würde die Liste sich nicht nur um die Speicherreservierung/Objekterstellung kümmern und nicht nur um die Freigabe, also die komplette Verwaltung. TDictionary<TKey,TValue> / TObjectDictionary<TKey,TValue> = Da man hier ja vorallem eine Fuchfunktion haben will ... Wie wäre es dann damit? :angel: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:37 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-2025 by Thomas Breitkreuz