Übersicht über Generics

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Generics - Index

Delphi unterstützt die Verwendung von Generics.

Funktionsweise von Generics

Die Begriffe Generics oder generische Typen beschreiben eine Reihe von Dingen, die in einer Plattform nach Typ parametrisiert werden können. Der Begriff Generics kann sich auf generische Typen und generische Methoden, d.h. generische Prozeduren und generische Funktionen, beziehen.

Generics sind eine Menge von Abstraktions-Tools, die eine Entkoppelung eines Algorithmus (Prozedur, Funktion) oder einer Datenstruktur (Klasse, Interface, Record) von einem oder mehreren bestimmten Typen zulassen, die der Algorithmus oder die Datenstruktur verwendet.

Eine Methode oder ein Datentyp, der andere Typen in seiner Definition verwendet, kann allgemeiner gehalten werden, wenn ein oder mehrere bestimmte Typen durch Typparameter ersetzt werden. Diese Typparameter werden dann in der Deklaration der Methode oder Datenstruktur einer Typparameterliste hinzugefügt. Dies ist vergleichbar mit dem Verallgemeinern einer Prozedur, wobei Instanzen einer literalen Konstante in deren Rumpf durch einen Parameternamen ersetzt werden, und der Parameter der Parameterliste der Prozedur hinzugefügt wird.

Zum Beispiel: Eine Klasse TMyList, die eine Liste von Objekten (des Typs TObject) verwaltet, kann wiederverwendbarer und typsicher gemacht werden, indem die Vorkommen von TObject durch einen Typparameternamen (z.B. 'T') ersetzt werden und der Typparameter der Typparameterliste der Klasse hinzugefügt wird, so dass daraus TMyList<T> wird.

Bestimmte Verwendungen (Instantiierungen) eines generischen Typs oder einer generischen Methode können festgelegt werden, indem für den generischen Typ oder die generische Methode Typargumente bereitgestellt werden. Die Bereitstellung von Typargumenten erstellt einen neuen Typ oder eine neue Methode. Dazu werden Instanzen des Typparameters in der generischen Definition durch das entsprechende Typargument ersetzt.

Beispielsweise könnte die Liste als TMyList<Double> verwendet werden. Somit wird der neue Typ TMyList<Double> erstellt, dessen Definition mit TMyList<T> identisch ist, außer dass alle Instanzen von 'T' in der Definition durch 'Double' ersetzt werden.

Generics als Abstraktionsmechanismus duplizieren einen Großteil der Funktionalität des Polymorphismus, aber mit unterschiedlichen Merkmalen. Da ein neuer Typ oder eine neue Methode bei der Instantiierung erstellt wird, können Typfehler schneller gefunden werden, nämlich bereits beim Compilieren und nicht erst bei der Ausführung. Dies vergrößert auch den Optimierungsbereich, aber mit einem Nachteil: Jede Instantiierung erhöht die Speicherauslastung der Anwendung mit dem möglichen Ergebnis einer geringeren Ausführungsgeschwindigkeit.

Codebeispiele

TSIPair ist eine Klasse, die zwei Datentypen enthält, String und Integer:

 type
   TSIPair = class
   private
     FKey: String;
     FValue: Integer;
   public
     function GetKey: String;
     procedure SetKey(Key: String);
     function GetValue: Integer;
     procedure SetValue(Value: Integer);
       property Key: TKey read GetKey write SetKey;
       property Value: TValue read GetValue write SetValue;
   end;

Damit eine Klasse unabhängig vom Datentyp wird, ersetzen Sie den Datentyp durch einen Typparameter:

 type
   TPair<TKey,TValue> = class   // declares TPair type with two type parameters
 
   private
     FKey: TKey;
     FValue: TValue;
   public
     function GetKey: TKey;
     procedure SetKey(Key: TKey);
     function GetValue: TValue;
     procedure SetValue(Value: TValue);
     property Key: TKey read GetKey write SetKey;
     property Value: TValue read GetValue write SetValue;
   end;
 
 type
   TSIPair = TPair<String,Integer>; // declares instantiated type
   TSSPair = TPair<String,String>;  // declares with other data types
   TISPair = TPair<Integer,String>;
   TIIPair = TPair<Integer,Integer>;
   TSXPair = TPair<String,TXMLNode>;

Anforderungen für und Unterschiede bei Plattformen

Generics werden von den Delphi-Compilern unterstützt.

Laufzeittypidentifikation

In Win32 verfügen parametrisierte Typen und Methoden über keine Laufzeittypinformationen (RTTI), instantiierte Typen dagegen schon. Ein instantiierter Typ ist die Kombination eines parametrisierten Typs mit einer Reihe von Parametern. Die RTTI für Methoden einer Klasse sind eine Untermenge der RTTI für diese Klasse im Ganzen. Hat eine nicht generische Klasse eine generische Methode, wird diese Methode nicht in die für die Klasse generierten RTTI einbezogen, weil Generics beim Compilieren und nicht zur Laufzeit instantiiert werden.

Interface-GUID

In Win32 haben instantiierte Interface-Typen keine Interface-GUID.

Parametrisierte Methoden in Interfaces

Eine parametrisierte Methode (Methode, die mit Typparametern deklariert ist) kann nicht in einem Interface deklariert werden.

Zeitpunkt der Instantiierung

Parametrisierte Typen werden beim Compilieren instantiiert und in die ausführbaren und verschiebbaren Dateien ausgegeben. Instanzvariablen eines generischen Typs werden für Klassen zur Laufzeit und für generische Records beim Compilieren instantiiert. Die RTTI für generische Klassen werden erst bei der Instantiierung der Klassen generiert. Die RTTI für instantiierte Klassen entsprechen denen für nicht generische Klassen. Wenn die generische Klasse eine generische Methode hat, dann verfügt die instantiierte generische Klasse über keine RTTI für diese generische Methode.

Dynamische Instantiierung

Es wird keine dynamische Instantiierung zur Laufzeit unterstützt.

Interface-Einschränkungen

Das Win32-Interface ist kein "leichtes" Interface. Das bedeutet, dass alle Typparameter mit Interface-Einschränkungen immer die COM IUnknown-Methoden _AddRef, _Release und QueryInterface unterstützen oder von TInterfacedObject erben. Record-Typen können keinen Interface-Einschränkungsparameter festlegen.

Siehe auch