![]() |
Wie dynamischer Vorfahr für generische Klasse?
Praktisch möchte ich sowas haben,
Delphi-Quellcode:
aber Delphi meint nur
TMyClass<Ancestor: Class> = Class(Ancestor)
* ^^^^^^^^ Zitat:
z.B.
Delphi-Quellcode:
wobei es quasi dem entspricht, nur daß eben meine gen. Klasse hier noch mit dazwischen eingefügt wird.
TTest = Class(TMyClass<TComponent>)
Delphi-Quellcode:
TTest = Class(TComponent)
|
Re: Wie dynamischer Vorfahr für generische Klasse?
Ich fürchte, da wirst du zur Zeit kein Glück haben. Mach dafür doch ein Feature-Request in QC auf.
Eventuell kannst du das aber mit Aggregation oder einem Decorator lösen. |
Re: Wie dynamischer Vorfahr für generische Klasse?
Nee, andere Wege helfen hier leider nichts,
denn wenn z.B. TMyClass direkt von TObject abgeleitet ist (alles Andere wäre Aufgrund des "unbekannten" Basistyps nicht sinvoll), dann hätte auch TTest nur TObject als Vorfahre und wäre dann, laut dem Beispiel, nicht mit TComponent kompatibel und somit kann man diese Klasse auch nicht als "Komponente" einsetzen. |
Re: Wie dynamischer Vorfahr für generische Klasse?
Zitat:
Ich kann mir nicht so richtig vorstellen, welche Funktionalität auf beliebige Klassen vererbt werden soll. Welche Funktionalität ist so allgemein nützlich, dass man sie im Prinzip in jeder Klasse brauchen kann? (etwa Logging oder Persistenz der Objektdaten?) |
Re: Wie dynamischer Vorfahr für generische Klasse?
Man kann auch Typschranken für Generics angeben, das müsste dann aber so aussehen
Delphi-Quellcode:
Das legt fest, dass alle Klassen mit denen du deinen generische Klasse initialisierst vom Typ TAncester oder eine davon abgeleitete Klasse sein muss.
TMyClass<A:TAncestor> = Class(TAncestor)
Wenn du class als Schranke angibst kannste du das auch gleich weglassen. Zitat:
EDIT: Aber andereseits, wenn du nur Funktionalität für Klassen die von der Klasse selbst abgeleietet sind anbieten möchtest brauchst du doch garkeine generics, da ein Obertyp der Klasse bekannst ist und die dynamische Bindung den Rest erledigen sollte. |
Re: Wie dynamischer Vorfahr für generische Klasse?
Neee, det "Basistyp ist eben hier noch nicht festgelegt, dieser ist in der generischen Klasse noch unbekannt und wird erst in der Ableitung entschieden.
Ich wollte auf diese Weise eine allgemeine Verwaltung einer verketteten Liste implementieren. Bei dieser Verwaltung ist der "Basistyp" unwichtig. Das : Class soll nur sicherstellen, daß dort nur irgendeine Klasse angegeben werden kann, aber welche Klasse das nun sein soll, ist ja nicht wichtig. |
Re: Wie dynamischer Vorfahr für generische Klasse?
Und was spricht gegen sowas?
Delphi-Quellcode:
type
TListNode<T> = class private FData: T; FNext: TListNode<T>; FPrev: TListNode<T>; public property Data: T read FData write FData; property Next: TListNode<T> read FNext write FNext; property Prev: TListNode<T> read FPrev write FPrev; end; |
Re: Wie dynamischer Vorfahr für generische Klasse?
@Uwe:
Delphi-Quellcode:
Das ist halt mein Problem.
var X: TListNode<TStringList>;
if X is TStringList then // geht nicht, da keine Stringliste Ich möchte den Basistypen ändern und nicht irgendeinen inneren Typen und dafür muß man den Basistypen von TListNode ändern.
Delphi-Quellcode:
TListNode<T> = class(Basistyp)
|
Re: Wie dynamischer Vorfahr für generische Klasse?
Schaut wie
![]() |
Re: Wie dynamischer Vorfahr für generische Klasse?
Zitat:
Delphi-Quellcode:
if X.Data is TStringList then
|
Re: Wie dynamischer Vorfahr für generische Klasse?
Zitat:
Delphi-Quellcode:
Und sag jetzt nicht,
procedure Proc(SL: TStrings);
begin end; var X: TListNode<TStringList>; Proc(X); // geht auch nicht, da keine Stringliste Zitat:
Außerdem finde ich es mit den .data im Code dann etwas unübersichtlich/umständlich. |
Re: Wie dynamischer Vorfahr für generische Klasse?
Ich frag mich gerade, wie die Implementierung deiner Klasse aussehen soll, wenn du dort nichtmal weißt, wovon sie abgeleitet ist. Dazu müsstest du doch zumindest einen Constraint angeben, oder nicht?
|
Re: Wie dynamischer Vorfahr für generische Klasse?
Zitat:
|
Re: Wie dynamischer Vorfahr für generische Klasse?
Wenn du sagst, deine Basisklasse ist nicht bekannt, dann meist du damit, dass diese auch eine generische Klasse ist? Oder wie istdas sonst zu verstehen
Zitat:
Delphi-Quellcode:
oder allgemeiner
procedure Proc(SL: TListNode<TStringList>);
begin end; var X: TListNode<TStringList>; Proc(X); // geht auch nicht, da keine Stringliste
Delphi-Quellcode:
procedure Proc(SL: TListNode<Y>);
begin end; var X: TListNode<TStringList>; Proc(X); // geht auch nicht, da keine Stringliste |
Re: Wie dynamischer Vorfahr für generische Klasse?
Zitat:
Delphi-Quellcode:
Welche Gemeinsamkeiten hätte denn TMyClass<TForm> mit TMyClass<TFoo> (bewusst nicht definierte Klasse gewählt) außer, dass beide explizit auf mindestens TMyClass<TObject> umgecastet werden könnten? Beziehungsweise, wozu muss der Typparameter der Vorfahr der Klasse sein? Nur, damit du ein Object davon an eine Methode übergeben kannst, die TForm bzw TFoo akzeptiert? Das geht auch anders.
TMyClass<Ancestor: class> = class(Ancestor)
|
Re: Wie dynamischer Vorfahr für generische Klasse?
Zitat:
Was Du haben willst sind Interfaces. Und um Methoden zur Verfügung zu stellen benutzt Du dann Extension Methods (Class helper) auf diesem Interface. Somit können alle von ihrer gewünschten Basisklasse ableiten, das Interface implementieren (das kann auch einfach leer sein, wenn es nur um Methoden geht) und aufgerufen werde diese Methoden über die Class helper auf dem Interface. |
Re: Wie dynamischer Vorfahr für generische Klasse?
Zitat:
Nja, ich hab mir hier halt ein Problem geschaffen und versuche dafür nun eine "nette" Lösung zu finden. Nja, ich werde noch etwas rumspielen ... mal sehn, vielleicht finde ich ja noch eine andere Lösung, außer dem Interface. Ich spiele grad so ein bissl rum und probiere mehreres aus. So war ich erstmal bei den "kleineren" Records gelandet, aber so wie es aussieht, werde ich wohl oder übel auf Klassen umsteigen müssen, weswegen ich dann auf das oben genannte "Problem" gekommen bin.
Delphi-Quellcode:
Allerdings geht auch das nicht, obwohl hier Typ ja bekannt wäre.
PMyRec = ^TMyRec<Typ: record>; // <<< geht natürlich nicht
// aber das war ja klar TMyRec<Typ: Record> = record type PTyp = ^Typ; // <<< geht {...} end;
Delphi-Quellcode:
Wie soll man da einen Pointer deklarieren, welchen auch der generische Teil kennt?
TMyRec<Typ: record> = record
type PMyRec = ^TMyRec<Typ>; // <<< geht nicht PTyp = ^Typ; // <<< geht {...} end; OK, außer man macht es umständlicher extern, welches aber nicht unbedingt eine "fehlerunanfälligere" Deklaration erfordert.
Delphi-Quellcode:
Und da Records keine Vererbung kennen, kann man hier ja keinen genaueren Typen festlegen, welcher dann ein "Value" kennt:
TMyRec<Typ: record; PRec> = record
type PMyRec = PRec; PTyp = ^Typ; {...} end; PTest = ^TTest; TTest = TMyRec<Integer, PTest>;
Delphi-Quellcode:
Selbst wenn sichergestellt ist, daß der Record "Typ" einen Wert "Value" besietzt, geht dieses nicht,
TMyRec<Typ: record> = record
x: Typ; function Test: Integer; end; function TMyRec<Typ>.Test: Integer; begin Result := X.Value; // <<< geht nicht end; da der Compiler dennoch meckert, daß "Value" nicht bekannt sei. [add] Und Generics für Helper gehn leider auch nicht.
Delphi-Quellcode:
TMyRec<Typ: Record> = Record Helper for Typ
... end; TMyCls<Typ: Class> = Class Helper for Typ ... end; |
Re: Wie dynamischer Vorfahr für generische Klasse?
Wieso bist Du so auf Generics versessen?
Die haben zwar ihre Daseinsberechtigung, sind aber kein Allheilmittel. Was willst Du denn eigentlich *genau* machen bzw. welches Problem hast Du Dir geschaffen was Du 'nett' Lösen willst? Vielleicht finden wir einen anderen / besseren Lösungsansatz der nicht das vergewaltigen von Sprachkonstrukten zum Inhalt hat? ;-) |
Re: Wie dynamischer Vorfahr für generische Klasse?
Zitat:
und "neue" Dinge müssen gründlich ausprobiert werden. Ja, und ich suche gern die Grenze des Möglichen und wenn möglich überschreite ich sie gerne mal. Wenn es nicht klappt, dann geht's halt nicht und ich löse es anders/normal. :angel2: Die Verwaltung einer mehrfach verketteten Liste ist ja nicht unbedingt sooooo einfach. Für sowas hab ich jetzt erstmal ein Template, welches man verwenden/anpassen könnte. Nun wollte ich das Ganze aber mal versuchen generisch zu lösen, so daß man es direkt einbinden und ohne Änderung verwenden könnte. |
Re: Wie dynamischer Vorfahr für generische Klasse?
Ist nur meine Meinung, aber ich halte es für keine gute Idee, die strukturelle Verknüpfung von Objekten in die Klassen zu verlagern. Das schränkt die Verwendbarkeit m.E. zu stark ein.
Beispiel: Nehmen wir die Klasse TStringList und leiten daraus einen TStringListNode ab, der dann für die verkettete Liste zuständig ist. Natürlich kann ich jetzt sowas wie Node is TStringList abfragen, aber was ist mit einer von TStringList abgeleiteten Klasse (z.B. TExtendedStringList)? Diese müsste eine neue Node-Ableitung bekommen TExtendedStringListNode. Das könnte wohl auch der Anlass zu deiner Frage gewesen sein. Nehmen wir nun mal an, es gäbe diesen Node-Generic. Nun brauchst du aber die Objekte nicht in einer verketten Liste, sondern in einer Baumstruktur. Geht aber nicht, weil du nicht einfach aus den ListNode-Instanzen TreeNode-Instanzen machen kannst. Wenn du die Struktur-Elemente aus den Klassen heraus hälst, gewinnst du wesentlich mehr Spielraum (Playboy!). |
Re: Wie dynamischer Vorfahr für generische Klasse?
Liste der Anhänge anzeigen (Anzahl: 4)
*ahhhhhhhhhhh* manchmal könnte man einfach nur schreien :wall:
Hab mal alles etwas umgestellt, der Compiler meint es ginge jetzt, aber beim Erstellen eines Testprojektes, meint er urplötzlich nach dem Testcode (hier sogar nach dem END. der DPR)
Delphi-Quellcode:
Eigentlich hätte ja sowas ausgereicht, aber da es keine Möglichkeit gibt PTheRecord zu dereferenzieren...
[DCC Fataler Fehler] Project4.dpr(23): F2084 Interner Fehler: AV21F90C39-W00000014-1
Delphi-Quellcode:
Nja, und Pointer ist keine gültige Beschränkung.
TDoubleLinkedList<PTheRecord {: ^Record}> = Record
Delphi-Quellcode:
TDoubleLinkedList<PTheRecord: Pointer> = Record
Wenn ich aber nur den Record übergebe und den Pointer intern deklariere,
Delphi-Quellcode:
dann schlägt im Testcode die stenge Typenprüfung von Delphi zu
TDoubleLinkedList<TheRecord: Record> = Record
Private Type PTheRecord = ^TheRecord;
Delphi-Quellcode:
[DCC Fehler] Project4.dpr(19): E2010 Inkompatible Typen: 'PMyRec' und 'TDoubleLinkedList<TMyRec>.PTheRecord'
So, den Rest der Woche werde ich wohl keine, bzw. nicht genug Zeit haben, um (richtig) zu Programmieren. :? Also mal sehn wann/ob ich hier wieder dazukomme weiterzumachen. [edit] OK, wenn man auf die Idee kommt, den internen Pointer rauszulassen, dann geht es urplötzlich :stupid:
Delphi-Quellcode:
anstatt
TMyRec = Record
List: TDoubleLinkedList<TMyRec>; Data: Integer; End; PMyRec = TDoubleLinkedList<TMyRec>.PRecord;
Delphi-Quellcode:
PMyRec = ^TMyRec;
TMyRec = Record List: TDoubleLinkedList<TMyRec, PMyRec>; Data: Integer; End; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:23 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