RAD Studio (Common)
|
The declaration of a generic is similar to the declaration of a regular class, record, or interface type. The difference is that a list of one or more type parameters placed between angle brackets (< and >) follows the type identifier in the declaration of a generic.
Type parameters can be used as a typical type identifier inside the container type declaration and method body.
For example:
type TPair<Tkey,TValue> = class // TKey and TValue are type parameters FKey: TKey; FValue: TValue; function GetValue: TValue; end; function TPair<TKey,TValue>.GetValue: TValue; begin Result := FValue; end;
Generic types are instantiated by providing type arguments. In Delphi for .NET, you can use any type as a type argument except for the following: a static array, a short string, or a record type that (recursively) contains a field of one or more of these two types.
type TFoo<T> = class FData: T; end; var F: TFoo<Integer>; // 'Integer' is sthe type argument of TFoo<T> begin ,,, end.
A nested type within a parameterized type is itself also a parameterized type.
type TFoo<T> = class type TBar = class X: Integer; // ... end; // ... TBaz = class type TQux<T> = class X: Integer; // ... end; // ... end;
To access the TBar nested type, you must specify a construction of the TFoo type first:
var N: TFoo<Double>.TBar;
A parameterized type can also be declared within a regular class as a nested type:
type TOuter = class type TData<T> = class FFoo1: TFoo<Integer>; // declared with closed constructed type FFoo2: TFoo<T>; // declared with open constructed type FFooBar1: TFoo<Integer>.TBar; // declared with closed constructed type FFooBar2: TFoo<T>.TBar; // declared with open constructed type FBazQux1: TBaz.TQux<Integer>; // declared with closed constructed type FBazQux2: TBaz.TQux<T>; // declared with open constructed type ... end; var FIntegerData: TData<Integer>; FStringData: TData<String>; end;
The base type of a parameterized class or interface type might be an actual type or a constructed type. The base type might not be a type parameter alone.
type TFoo1<T> = class(TBar) // Actual type end; TFoo2<T> = class(TBar2<T>) // Open constructed type end; TFoo3<T> = class(TBar3<Integer>) // Closed constructed type end;
If TFoo2<String> is instantiated, an ancestor class becomes TBar2<String>, and TBar2<String> is automatically instantiated.
Class, interface, and record types can be declared with type parameters.
For example:
type TRecord<T> = record FData: T; end; type IAncestor<T> = interface function GetRecord: TRecrod<T>; end; IFoo<T> = interface(IAncestor<T>) procedure AMethod(Param: T); end; type TFoo<T> = class(TObject, IFoo<T>) FField: TRecord<T>; procedure AMethod(Param: T); function GetRecord: TRecord<T>; end;
The procedure type and the method pointer can be declared with type parameters. Parameter types and result types can also use type parameters.
For example:
type TMyProc<T> = procedure(Param: T); TMyProc2<Y> = procedure(Param1, Param2: Y) of object; type TFoo = class procedure Test; procedure MyProc(X, Y: Integer); end; procedure Sample(Param: Integer); begin WriteLn(Param); end; procedure TFoo.MyProc(X, Y: Integer); begin WriteLn('X:', X, ', Y:', Y); end; procedure TFoo.Test; var X: TMyProc<Integer>; Y: TMyProc2<Integer>; begin X := Sample; X(10); Y := MyProc; Y(20, 30); end; var F: TFoo; begin F := TFoo.Create; F.Test; F.Free; end. var F: TFoo; begin F := TFoo.Create; F.Test; F.Free; end.
Methods can be declared with type parameters. Parameter types and result types can use type parameters Parameterized methods are similar to overloaded methods.
There are two ways to instantiate a method:
For example:
type TMyProc2<Y> = procedure(Param1, Param2: Y) of object; TFoo = class procedure Test; procedure MyProc2<T>(X, Y: T); end; procedure TFoo.MyProc2<T>(X, Y: T); begin Write('MyProc2<T>'); {$IFDEF CIL} Write(X.ToString); Write(', '); WriteLn(Y.ToString); {$ENDIF} WR end; procedure TFoo.Test; var P: TMyProc2<Integer>; begin MyProc2<String>('Hello', 'World'); MyProc2('Hello', 'World'); MyProc2<Integer>(10, 20); MyProc2(10, 20); P := MyProc2<Integer>; P(40, 50); end; var F: TFoo; begin F := TFoo.Create; F.Test; F.Free; end.
The scope of a type parameter covers the type declaration and the bodies of all its members, but does not include descendent types.
For example:
type TFoo<T> = class X: T; end; TBar<S> = class(TFoo<S>) Y: T; // error! unknown identifier "T" end; var F: TFoo<Integer>; begin F.T // error! unknown identifier "T" end.
Copyright(C) 2008 CodeGear(TM). All Rights Reserved.
|
What do you think about this topic? Send feedback!
|