Stacks und Queues Besondere Datentypen

Object Pascal im Detail - Besondere Datentypen www.delphi-treff.de 134 uses Generics.Collections; procedure TForm1.MyMethod; var MyDict: TDictionaryInteger, string; Value: String; begin MyDict := TDictionaryInteger, string.Create; try MyDict.Add1, Eins ; MyDict.Add2, Zwei ; Value := MyDict.Items[2]; Value enthält nun den Wert ‚Zwei‘ MyDict.AddOrSetValue2, Neue Zwei ; Value := MyDict.Items[2]; Value enthält nun den Wert ‚Neue Zwei‘ MyDict.Add2, 2 ; Exception EListError wird geworfen, weil Key 2 schon existiert Zum Auslesen von Werten aus einem Dictionary gibt es verschiedene Methoden. Eine davon haben wir in obigem Beispiel schon gesehen: Items gefolgt vom Key in eckigen Klammern. In unserem Fall sind die Keys vom Typ Integer, weshalb in eckigen Klammern ein Integer steht. Rückgabewert ist der Wert, der zu dem Key gehört in unserem Fall ein String. Existiert der gesuchte Schlüssel im Dictionary allerdings nicht, wird eine EListError-Exception geworfen. Das kann man verhindern, indem man vorher prüft, ob der Schlüssel existiert: ContainsKey. if MyDict.ContainsKey3 then Value := MyDict.Items[3]; Will man sich das Überprüfen sparen, kann man die Methode TryGetValue verwenden, die als zweites Argument einen Out-Parameter bekommt. Die Methode an sich gibt true oder false zurück, je nach dem, ob der Schlüssel gefunden wurde oder nicht. var value: string; begin MyDict.TryGetValue1, value; Normalerweise wird auf den Inhalt von Dictionaries über die Schlüssel zugegriffen, die eindeutig sind. Es kann aber unter Umständen sinnvoll sein, auch nach dem Vorhandensein von Werten zu suchen. Auch das unterstützt TDictionary: if MyDict.ContainsValue ‘Zwei‘ then ...

4.12.4. Stacks und Queues

Die RTL enthält weitere Klassen außer TList und TDictionary, um Mengen von Werten bzw. Objekten zu verwalten. Zu erwähnen sind TStack und TQueue. Beide verwalten ihre Elemente in einer festen Reihenfolge und sind in der Unit System.Generics.Collections zu finden. Object Pascal im Detail - Besondere Datentypen www.delphi-treff.de 135 Bei einem Stack Stapel werden neue Elemente immer oben drauf gelegt Push und beim Auslesen immer das oberste Element wieder entfernt Pop. Das entspricht dem sog. LIFO- P i zip „Last i fi st out . Das letzte Element das hinzugekommen ist, wird als erstes wieder entfernt. Anders ist es bei der Warteschlange Queue. Hier werden neue Elemente immer hinten angestellt Enqueue, während beim Auslesen vorne beim ältesten Element begonnen wird Dequeue. Das entspricht dem FIFO- P i zip „Fi st i fi st out . Das Ele e t, das als e stes hi zugefügt o de ist, i d au h als e stes iede entfernt. Object Pascal im Detail - Ge e is he Date t pe „Ge e i s www.delphi-treff.de 136

4.13. Ge erische Date type „Ge erics“

Delphi unterstützt seit Version 2009 generische Datentypen. Diese werden gebraucht, um Datentypen sehr allgemein programmieren zu können, ohne dass sie dadurch in der Anwendung kompliziert werden. Ein gutes Beispiel dafür sind Listen. In Delphi gibt es dafür schon seit langer Zeit die Klasse TList. TList sollte in jeder Lebenslage einsetzbar sein, weshalb alle enthaltenen Elemente als Pointer aufgefasst werden. Ein Pointer zeigt auf eine Adresse im Arbeitsspeicher. Was dort zu finden ist, muss der Programmierer selbst wissen. D.h. beim Auslesen muss das Element in einen bestimmten Typ umgewandelt werden. Das ermöglicht es einem Programmierer nun tatsächlich, Objekte beliebigen Typs in eine Liste zu stecken. Allerdings gibt es nun zwei Probleme: Üblicherweise enthalten Listen nur Elemente des gleichen Typs, z.B. eine Liste von Strings. Das kann TList aber nicht sicherstellen. Dadurch ist es möglich, Objekte völlig unterschiedlicher Typen absichtlich oder unabsichtlich in dieselbe Liste zu stecken. Auf das andere Problem stößt man beim Auslesen der Liste: TList gibt alles als Pointer zurück. Der Programmierer muss das Objekt also selbst in das casten, was er eigentlich erwartet, was umständlich und fehleranfällig ist. Wie wäre es also, wenn man der Liste schon beim Erzeugen sagen könnte, dass sie nur Strings aufnehmen und zurückgeben soll? Und in einer anderen Instanz nur Integers? Genau das ist der Einsatzzweck für Generics. Wer auch die vorhergehenden Kapitel gelesen hat, kennt das Vorgehen schon. Hier trotzdem noch einmal das Beispiel: var MyList: TListInteger; MyList ist nun eine Liste, die ausschließlich Integer-Werte aufnehmen kann. Beim Auslesen der Liste kommen direkt Integer-Werte zurück, die nicht gecastet werden müssen. Selbstverständlich sind auch weitere Verwendungen möglich: MyStringList: TListstring; TList ist also eine generische Klasse. Doch wie macht sie das? Die Klasse TList weiß vor ihrer Instanziierung nicht, für welchen Datentyp sie zuständig sein soll. Deshalb können die Methoden in TList nicht mit einem bestimmten Typ arbeiten, auch nicht mit TObject. Stattdessen wird ein Platzhalter verwendet, üblicherweise kommt hier der Großbuchstabe T zum Einsatz. Allerdings können auch beliebige andere Pascal-Bezeichner verwendet werden. Die Klassendefinition von TList könnte also so aussehen beispielhafte Implementierung, nicht an der Original-TList-Klasse orientiert: